文字列を表す型には複数あり,データ型が異なればデータの格納方法が異なる。また,NULL値はゼロでも空白文字でもない特殊な値である。これらの特性を把握していなければ,予期せぬ結果を招くことがある。特性を知った上で,SQL関数を適切に使うことが必要だ。一方,複数カラムのデータからなる複合インデックスは,検索において効果的な使い方ができる半面,使われ方にくせがある。それを知らなければ,使っているつもりで使えてなかった,などの事態に陥りかねない。
SQL文を利用する際に注意すべき基礎的なポイントを解説するセミナーの第2回である。前回は,条件句(WHERE*句),演算の優先順位,レコードの順番にまつわる注意点を説明した。SQLは,C++やJavaなどのプログラミング言語と異なる特性を持ち,その特性の違いを意識していなければ落とし穴にはまりやすい,と説明した*1 。
今回は,SQLの文字列型,NULL*値,複合インデックス*にまつわる注意点を説明する(図1[拡大表示])。文字列型やNULL値の落とし穴を回避するには,それらの特性を知った上で,SQL関数をうまく使うことが必要である。随時,SQL関数の使い方を説明する*2。なおRDBMSは,筆者の利用経験の多いOracleをベースとする。実行結果などはすべてOracle上で稼働したものになるが,基本的にはほかのRDBMSでも同様である。
●文字列型 同じ文字列でもデータ型が異なれば別物 |
Oracleの文字列データ型には,(1)固定長の「CHAR」型と,(2)可変長の「VARCHAR2」型の2種類がある。Oracleに文字列を格納するには,このどちらかのデータ型を選ぶことになる。
2種類のデータ型があることによって,同じ文字列でも文字列の長さが異なったり,文字列の比較が正しく行われなかったりする。なぜそうなるかを理解するには,2種類のデータ型のデータ格納方法を知っておかなければならない。
データ格納方法が異なる
「CHAR」型は,あらかじめ指定した文字数の領域を固定的に確保する,“固定長”のデータ型である。一方の「VARCHAR2」型は,文字列を格納するのに必要な文字数分の領域しか確保しない,“可変長”のデータ型だ。
例えば,5文字を格納するデータ型を定義し,そのデータ型に3文字を格納する場合を考えてみよう。固定長のCHAR型は,5文字分の領域を確保し,先頭から3文字分の領域に文字を入れる。余った2文字分の領域には,空白文字が入る((図2上)[拡大表示])。一方,可変長のVARCHAR2型は,3文字分の領域を確保し,3文字を格納する(同下)*3。
では,CHAR型とVARCHAR2型をどう使い分ければよいのだろうか。単純に文字列を格納するのに必要なディスク容量だけを考えると,CHAR型よりもVARCHAR2型の方がコンパクトに格納できる分,優れていると言える。しかしVARCHAR2型には,「データを更新するとデータの格納状態が悪化する可能性が高い」という欠点がある。更新後の文字列が更新前の文字列よりも長い場合,更新前に使っていたディスク領域に文字列を格納することができない。同じデータ・ブロック*に空きがあればそこを利用するが,それでも格納できない場合,ほかのデータ・ブロックにデータを格納する。これはディスクI/Oを増加することになり,パフォーマンスの低下を招く。
そのため,2つのデータ型は,格納するデータの特性を考えて使い分ける。文字列の長さがある程度そろう場合や,更新の可能性があって,かつ,最大文字数が決めやすい場合には固定長のCHAR型が適する。例えば住所などは変更が発生しやすく最大文字数が決めやすいのでCHAR型にすべきだろう。一方,格納する文字列の長さがばらばらだったり,参照することがメインで更新が少ない場合には,可変長のVARCHAR2型が適する。営業日報の自由報告欄などが,その典型的な例である。
同じ文字列でも“等しくない”
このように格納方法が異なるため,(1)文字列の長さと(2)文字列の比較判定において,データ型の違いによる注意が必要となる。
文字列の長さは,CHAR型ではデータ型の文字数のことになる。実際の文字は3文字しかなくても,データ型が5文字分あれば,空白文字が挿入されるため文字列長さは「5」になる。一方のVARCHAR2型では,データ型の定義にかかわらず,実際に格納している文字数が文字列の長さになる。同じ文字列であっても,データ型が異なれば文字列長さは異なることがあるのだ(図3(2)[拡大表示])。
文字列の比較においては,同じデータ型同士であれば問題は起きない。CHAR型同士,または,VARCHAR2型同士の文字列を比較する場合,データの格納方法が同じであるため,同じ文字列の比較は等しいと判断される。また,CHAR型と固定文字列,VARCHAR2型と固定文字列の比較においても,文字列の比較は正しく判定される(同(3))。
問題は,CHAR型とVARCHAR2型を比較する場合である。この場合,同じ文字列でも“等しくない”と判定されることがある。図3(4)の場合,CHAR型のデータは「A」「B」「C」と空白2文字の5文字の文字列で,VARCHAR2型のデータは「A」「B」「C」の3文字の文字列になり,この2つの文字列の比較は“等しくない”と判定される。
CHAR型とVARCHAR2型を比較する場合,CHAR型に自動的に挿入される空白文字が正しい判定を妨げている。正しく比較するには,CHAR型の空白文字を取り除いて比較する必要がある。空白文字を取り除くには,TRIM 関数*を使えばよい。TRIM関数の引数にCHAR型のデータを指定し,その戻り値とVARCHAR2型を比較する。図3(4)の場合,
SELECT *
FROM TEST
WHERE TRIM(C1) = C2 ;
とすれば,正しい比較判定が行える。
玉川 敏一(たまがわ としいち) 1980年代後半からリレーショナル・データベースを利用している。当初は汎用機上のRDBMSであったが,1994年(株)シーズ・ラボ入社以来,Oracle一筋になる。同社にてシステム開発,研修インストラクタ,サポート窓口,技術支援業務を行い,Oracleと深くかかわっている。Oracle Master Platinum資格を保有。 |