式の評価における型変換
式内の演算子が異なる型のオペランドと一緒に使用される場合、オペランド間の互換性を確保するためにデータ型の変換が行われます。
変換方法
OceanBaseデータベースは、明示的なデータ型変換と暗黙的なデータ型変換をサポートしています。
暗黙的なデータ型変換は、次のようなシナリオで発生します。ある操作に指定されたデータ型のパラメータが必要ですが、ステートメントの実際のパラメータ値は指定されたデータ型ではありません。この場合、OceanBaseデータベースは実際のパラメータ値を指定されたデータ型に変換した後、その後の操作を実行します。
以下の例のように、OceanBaseデータベースは必要に応じて文字列を数値に自動的に変換し、その逆も同様です。
obclient> SELECT 1+'1';
+-------+
| 1+'1' |
+-------+
| 2 |
+-------+
1 row in set
OceanBaseデータベースの明示的なデータ型変換は、CAST関数を使用して実現されます。以下の例を参照してください:
obclient> SELECT 31.4, CAST(31.4 AS TIME);
+------+--------------------+
| 31.4 | CAST(31.4 AS TIME) |
+------+--------------------+
| 31.4 | 00:00:31 |
+------+--------------------+
1 row in set
CAST関数の詳細については、CASTを参照してください。
変換ルール
比較演算の変換ルール
1つまたは2つの引数が
NULL場合、比較結果はNULLとなりますが、<=>比較演算子は例外です。NULL <=> NULLの場合、結果は真であり、変換は不要です。比較演算において両方の引数が文字列の場合、それらは文字列として比較されます。
両方の引数が整数の場合、それらは整数として比較されます。
数値と比較されない場合、16進数値はバイナリ文字列と見なされます。
1つまたは複数のテーブルからの単一行サブクエリは定数と見なされません。たとえば、サブクエリが返す整数を
DATETIME値と比較する場合、両オペランドは整数として扱われます。整数は時間値に変換されないため、オペランドをDATETIME値と比較するには、サブクエリ値を明示的にDATETIMEに変換するためにCAST()使用してください。一方の引数が
TIMESTAMPまたはDATETIME列で、もう一方の引数が定数の場合、比較を実行する前にその定数はタイムスタンプに変換されます。安全性を確保するため、比較時には常に完全な日付時刻、日付、または時間文字列を使用してください。たとえば、BETWEEN日付または時間値と一緒に使用する場合、最適な結果を得るには、値を明示的に必要なデータ型に変換するためにCAST()使用してください。一方の引数が小数点数値の場合、比較の種類はもう一方の引数によって決まります。もう一方の引数が小数点または整数値の場合、引数は小数点数値として比較され、もう一方の引数が浮動小数点数値の場合は浮動小数点数値として比較されます。
上記以外の場合、引数は浮動小数点(実数)として比較されます。たとえば、文字列と数値のオペランドの比較は浮動小数点数として比較されます。
浮動小数点数と
INTEGER型の大きな値との比較は近似されます。これは、整数が比較の前に倍長浮動小数点数に変換されるため、64ビット整数すべてを正確に表現できないためです。
タイプのダウングレード
比較セマンティクスを満たす条件のもとで、定数を可能な限り列タイプに整列させることで、効率的な比較を実現します。現在、標準セマンティクスに基づくほとんどの列と定数の比較がサポートされており、残りの場合は列にキャストを追加して比較します。これについては後述します:
intまたはuint列では、定数として文字列タイプ、decimalタイプ、浮動小数点数(double/float)タイプを整数型列にダウングレードできます。decimal列では、浮動小数点数(double/float)タイプをdecimal列にダウングレードできます。year列では、数値型(整数型、浮動小数点数、decimalタイプを含む)、文字列タイプ、日付時刻型(date、datetime、timestamp、timeなどを含む)をyear列にダウングレードできます。date列では、文字列タイプ、datetime、timestamp、timeタイプをdate列にダウングレードできます。timestamp列では、datetimeをtimestampにダウングレードできます。
現在、列にキャストを追加するシナリオ(array、xml、jsonなどの複雑なデータ型は除く)は以下の通りです:
float列では、float列の比較は常にdoubleで行われるため、float列と任意の定数を比較する際にはcastが追加されます。fixed double列では、テーブル作成時にpsを指定します。例えばdouble(10, 2)のように指定します。定数の小数点以下の桁数が多い場合、精度を揃えて比較するため、列にキャストが追加されます。- 文字列列では、文字列と数値型の比較は数値順で行われるため、列を数値型に
castします。また、文字セットの比較ルールによっても列にcastが追加される場合があります。
非標準比較
非標準比較のロジックは、データ型のダウングレード処理と似ており、定数と列の比較のみを処理し、列と列の比較については処理しません。現在、整数定数と文字列の比較のみがサポートされています。ただし、range に設定すると、ソート結果が標準的な意味に従わない可能性があるため、データの特性に応じて設定する必要があります。
以下の例を参照してください:
t1という名前のテーブルを作成しました。このテーブルには、biz_dayという名前の列があり、その型はvarchar(10)です。obclient> CREATE TABLE t1 (biz_day varchar(10)); Query OK, 0 rows affected (0.216 sec)デフォルトの実行計画を確認します。
obclient> EXPLAIN SELECT * FROM t1 WHERE biz_day BETWEEN 20200101 AND 20200201; +-------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +-------------------------------------------------------------------------------------------------------------------------------------------------+ | ====================================================== | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------ | | |0 |COLUMN TABLE FULL SCAN|T1 |2 |3 | | | ====================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([T1.BIZ_DAY]), filter([cast(T1.BIZ_DAY, NUMBER(-1, -85)) >= 20200101], [cast(T1.BIZ_DAY, NUMBER(-1, -85)) <= 20200201]), rowset=16 | | access([T1.BIZ_DAY]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false,false], | | range_key([T1.__pk_increment]), range(MIN ; MAX)always true | +-------------------------------------------------------------------------------------------------------------------------------------------------+ 11 rows in set (0.004 sec)- クエリプラン:デフォルトでは、クエリオプティマイザーは
biz_day列を文字列型から数値型に変換してから比較を行います。 - フィルター条件:
filter([cast(T1.BIZ_DAY, NUMBER(-1, -85)) > 20200101] AND [cast(T1.BIZ_DAY, NUMBER(-1, -85)) <= 20200201])は、biz_dayを数値に変換した後で範囲比較を行うことを意味します。
- クエリプラン:デフォルトでは、クエリオプティマイザーは
non_standard_comparison_levelをequalに設定して実行計画を確認します。obclient> EXPLAIN SELECT /*+opt_param('non_standard_comparison_level', 'equal')*/ * FROM t1 WHERE biz_day BETWEEN 20200101 AND 20200201; +----------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +----------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ====================================================== | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------ | | |0 |COLUMN TABLE FULL SCAN|t1 |1 |3 | | | ====================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([t1.biz_day]), filter([cast(t1.biz_day, DECIMAL(-1, -1)) >= cast(20200101, DECIMAL(20, 0))], [cast(t1.biz_day, DECIMAL(-1, -1)) <= cast(20200201, | | DECIMAL(20, 0))]), rowset=16 | | access([t1.biz_day]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false,false], | | range_key([t1.__pk_increment]), range(MIN ; MAX)always true | +----------------------------------------------------------------------------------------------------------------------------------------------------------------+ 12 rows in set (0.003 sec)- クエリプラン:
non_standard_comparison_levelをequalに設定すると、クエリオプティマイザーはbiz_day列を文字列型から小数点数値型に変換してから比較を行います。
- クエリプラン:
- フィルター条件:
filter([cast(t1.biz_day, DECIMAL(-1, -1)) >= cast(20200101, DECIMAL(20, 0))] AND [cast(t1.biz_day, DECIMAL(-1, -1)) <= cast(20200201, DECIMAL(20, 0))])は、biz_dayを小数点数値に変換した後で範囲比較を行うことを意味します。betweenは範囲クエリであるため、equalの等価比較ルールでは定数型を変換しません。
non_standard_comparison_levelをrangeに設定して実行計画を確認します。obclient> EXPLAIN SELECT /*+opt_param('non_standard_comparison_level', 'range')*/ * FROM t1 WHERE biz_day BETWEEN 20200101 AND 20200201; +-------------------------------------------------------------------------------------------------------------------------------------------------------+ | Query Plan | +-------------------------------------------------------------------------------------------------------------------------------------------------------+ | ====================================================== | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------------ | | |0 |COLUMN TABLE FULL SCAN|t1 |1 |3 | | | ====================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([t1.biz_day]), filter([t1.biz_day >= demote_cast(20200101, VARCHAR(10))], [t1.biz_day <= demote_cast(20200201, VARCHAR(10))]), rowset=16 | | access([t1.biz_day]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false,false], | | range_key([t1.__pk_increment]), range(MIN ; MAX)always true | +-------------------------------------------------------------------------------------------------------------------------------------------------------+ 11 rows in set (0.004 sec)- クエリプラン:
non_standard_comparison_levelをrangeに設定すると、クエリオプティマイザーは整数定数を文字列型に変換してから比較を行います。 - フィルター条件:
filter([t1.biz_day >= demote_cast(20200101, VARCHAR(10))] AND [t1.biz_day <= demote_cast(20200201, VARCHAR(10))])は、整数定数を文字列に変換した後で範囲比較を行うことを意味します。非標準比較後は、文字順で比較されます。例えば、'202002010'は文字順では['20200101', '20200201']に属しますが、数値順の[20200101, 20200201]の範囲には含まれません。
- クエリプラン:
その他の関連変換ルール
文字列から浮動小数点数への変換と整数から浮動小数点数への変換は、必ずしも同じではありません。結果はコンパイラのバージョンなどの要因によって影響を受ける可能性があります。このような問題を回避する方法の一つは、値が暗黙的に浮動小数点数に変換されないようにするために
CAST()を使用することです。数値または日付時刻値を文字列に暗黙的に変換すると、
character_set_connectionおよびcollation_connectionシステム変数によって決定される文字セットと照合順序を持つ値が生成されます。これは、このような変換がバイナリでない文字列(
CHAR、VARCHAR、またはLONGTEXT値)を生成することを意味します。接続文字セットをバイナリに設定した場合、変換結果はバイナリ文字列(BINARY、VARBINARY、またはLONGBLOB値)になります。整数式の評価時の型変換にはいくつかの違いがあります。例えば、CREATE TABLE ステートメントの一部として整数式を使用する場合、式の結果型に応じて、作成される新しいテーブルには
INTまたはBIGINT型の列が含まれます:CREATE TABLE t SELECT integer_expr;式の最大長が
INTに適さない場合は、BIGINTを使用します。ただし、十分に長い式を使用することで、INTの代わりにBIGINTを強制的に使用することができます:obclient> CREATE TABLE t SELECT 000000000000000000000; Query OK, 1 row affected
暗黙的なデータ型変換ルール
データ型の変換が意味を持つ場合、OceanBaseデータベースは値をあるデータ型から別のデータ型に自動的に変換します。
以下の表はすべてのデータ型の暗黙的変換マトリックスであり、変換の方向や文脈を考慮する必要はありません。
| データ型 | BOOL | INT | SMALLINT | MEDIUMINT | BIGINT | SERIAL | DECIMAL | NUMERIC | FLOAT | DOUBLE | BIT | DATETIME | TIMESTAMP | DATE | TIME | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| YEAR | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| CHAR | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| VARCHAR | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| BINARY | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| VARBINARY | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| TEXT | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| TINYBLOB | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| MEDIUMBLOB | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| LONGBLOB | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| TINYTEXT | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| MEDIUMTEXT | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| LONGTEXT | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| ENUM | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | |
| SET | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
| BLOB | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい | はい |
暗黙的なデータ型変換の例
obclient> SELECT CAST(BOOL_COLUMN AS YEAR) FROM YOUR_TABLE;
+---------------------------+
| CAST(BOOL_COLUMN AS YEAR) |
+---------------------------+
| 2001 |
+---------------------------+
2 rows in set (0.001 sec)