0. はじめに
OracleDatabaseで文字データ型の比較を行った際、
'abc⎵⎵' = 'abc' -- '⎵'は半角スペース
が等しいとみなされる場合とみなされない場合があったので、
どのような違いがあるのか調べました。
結論から言うと
CHARデータ型系同士1の比較の場合は'abc⎵⎵'と'abc'が等しいとみなされ、少なくとも一方がVARCHAR2データ型系2の場合はみなされません。
以下で詳しく説明します。
バージョン21cのSQL言語リファレンスをもとに書いていますので、DBのバージョンが異なる場合は注意してください。
結論のソースのみ確認したい方は、2 Oracleのデータ型>データ型の比較原則>文字値の
空白埋め比較セマンティクスおよび非空白埋め比較セマンティクスをご覧ください。
1. CHARデータ型
カラムのデータ型をCHARで指定した場合、固定長の文字列を格納できます。
カラム作成時にsize(列長)を指定し、格納された文字列はsizeで指定された長さになります。
登録しようとする値が、カラムの列長より短い場合は後方を空白埋めされ、
列長より長い場合はエラーになります。
冒頭の'abc⎵⎵'のような文字列が発生する状況としては、
CHARデータ型の列から値を取得しているケースが多いと思います。
この他、カラムの列長がバイト長を指しているのか、
それとも文字列長を指しているのかも重要なポイントですが、
ここでは意識しなくても話を進められるので一旦置いておきます。
CHARは固定長であり、格納した値が列長より短い場合は空白埋めされる
2. VARCHAR2データ型
カラムのデータ型をCHARで指定した場合、可変長の文字列を格納できます。
CHARデータ型同様、カラム作成時に列長を指定します。
登録しようとする値が、カラムの列長より短い場合は空白埋めせずにそのまま格納され、列長より長い場合はエラーになります。
CHAR型の列から列長と長さが等しい値を取得した場合や、VARCHAR2データ型の列から値を取得した場合、システムからパラメータを受け取った場合など、
冒頭の'abc'のような文字列が発生するケースは結構多いので、データの型に特に注意が必要です。
CHARデータ型同様、列の長さセマンティクスに関してはここでは割愛します。
VARCHAR2は可変長であり、格納した値が列長より短い場合も空白埋めされない
3. 文字値を戻すファンクション
データ型がCHARのカラムから値を取り出す場合であっても、
ファンクション(関数)を適用した場合、データ型が変わる可能性があります。
私が遭遇したケースでは、
CHARデータ型カラムから取得した値に、REPLACEを使用した結果、VARCHAR2データ型が戻されていました。
戻り値が文字データ型のファンクションはたくさんあるので、詳細は公式リファレンスを参照してください。
ファンクションが戻す値のデータ型に注意
4. 空白埋め比較セマンティクス
空白埋め比較セマンティクスとは、
比較対象の2つの値の長さが異なる場合、短い方の値を後方空白埋めして比較するセマンティクスです。
後方の空白のみが異なる(冒頭の'abc⎵⎵' = 'abc'のような)場合でも、
このセマンティクスが使用される場合は2つの値が等しいとみなされます。
最初に説明した通り、CHARデータ型系同士1の比較においてはこの空白埋め比較セマンティクスが使用されます。
空白埋め比較セマンティクスでは'abc⎵⎵' = 'abc'が等しいとみなされる
5. 非空白埋め比較セマンティクス
空白埋め比較セマンティクスに対して、
値の長さが異なる場合でも、空白埋めをせずに比較するセマンティクスを非空白埋め比較セマンティクスといい、非空白埋め比較セマンティクスが使用される場合は、
後方の空白のみが異なる場合、2つの値が異なっている(正確には長い方の値が大きい)とみなされます。
比較対象の2つの値のうち少なくとも一方がVARCHAR2データ型系2である場合には、非空白埋め比較セマンティクスが使用されます。
非空白埋め比較セマンティクスでは'abc⎵⎵' = 'abc'が等しくないとみなされる
6. まとめ
'abc⎵⎵' = 'abc'に関して、
CHARデータ型系同士1の比較の場合は、
空白埋め比較セマンティクスが使用されるため両辺が等しいとみなされ、
少なくとも一方がVARCHAR2データ型系2である場合には、
非空白埋めセマンティクスが使用されるため両辺が等しくないとみなされます。
DBやSQLで意図せぬ動作をした際には、データ型やファンクション、
比較規則等の仕様の確認が重要だと思いました。
以上