図4●SQLにおける算術演算と論理演算の優先順位
図4●SQLにおける算術演算と論理演算の優先順位
[画像のクリックで拡大表示]
図5●演算の優先順位にまつわるミスの例<BR>(1)は算術演算の優先順位にまつわるミス。足し算よりも掛け算の方が先に計算されるため,期待した結果が得られない。(2)は論理演算の優先順位にまつわるミス。ORよりもANDの方が優先されるため,期待した結果が得られない
図5●演算の優先順位にまつわるミスの例<BR>(1)は算術演算の優先順位にまつわるミス。足し算よりも掛け算の方が先に計算されるため,期待した結果が得られない。(2)は論理演算の優先順位にまつわるミス。ORよりもANDの方が優先されるため,期待した結果が得られない
[画像のクリックで拡大表示]
図6●SQL文を読みやすくする&lt;BR&gt;(1)句で改行する,(2)複数行の場合は字下げする,(3)テーブルの別名を利用する,(4)コメントを付ける――などによって,SQL文を読みやすくする
図6●SQL文を読みやすくする<BR>(1)句で改行する,(2)複数行の場合は字下げする,(3)テーブルの別名を利用する,(4)コメントを付ける――などによって,SQL文を読みやすくする
[画像のクリックで拡大表示]
図7●検索結果のレコードの順番にまつわる注意点(その1)&lt;BR&gt;検索結果の順番を明示的に指定しない限り,レコードの順番は不定となる。ある時たまたま期待通りの順番で出力していても,レコードの更新などがあると順番は変わってしまう。検索結果を意図的な順番で並べるには,ORDER BY句を使う
図7●検索結果のレコードの順番にまつわる注意点(その1)<BR>検索結果の順番を明示的に指定しない限り,レコードの順番は不定となる。ある時たまたま期待通りの順番で出力していても,レコードの更新などがあると順番は変わってしまう。検索結果を意図的な順番で並べるには,ORDER BY句を使う
[画像のクリックで拡大表示]
図8●検索結果のレコードの順番にまつわる注意点(その2)&lt;BR&gt;文字列カラムにORDER BY句を指定した場合,文字コードの順番になる。図のような場合,直感的に期待する順番とは異なる結果となる
図8●検索結果のレコードの順番にまつわる注意点(その2)<BR>文字列カラムにORDER BY句を指定した場合,文字コードの順番になる。図のような場合,直感的に期待する順番とは異なる結果となる
[画像のクリックで拡大表示]
(2)1行が長くなりやすい
  演算の優先順位に注意

 SQL文の1行は,C/C++などの汎用プログラミング言語に比べて長くなりやすい。SQL文は処理手続きを記述せず,1行にひとかたまりの処理内容を記述する。そのため複雑な条件を指定することになるからだ。1行が長いと,SQL文が読みにくくなるだけでなく,演算の優先順位にまつわるミスを起こしやすい。

迷ったときはカッコをつける

 SQLの算術演算,論理演算の優先順位は,汎用のプログラミング言語と基本的に同じである。足し算や引き算よりも,掛け算や割り算の方が優先順位が高い。また,SQL文では論理演算をよく使うが,その優先順位は高い方から,NOT,AND,ORの順になる(図4[拡大表示])。

 算術演算と論理演算の優先順位による,間違ったSQL文の例を示そう。(図5[拡大表示])(1)は,算術演算の優先順位を間違えた例である。「年収が300万円以上の社員」を検索するのに,間違えて,

SELECT SYAIN_NO, SYAIN_MEI
FROM SYAIN_TBL
WHERE KIHON + TEATE * 12 > 3000000 ;
としてしまった。計算したいことは,毎月の基本給(KIHON)と手当て(TEATE)の合計に,12を掛けて年収とし,300万円よりも多いかどうかを判定すること。しかしこのSQL文は正しくない。足し算よりも掛け算の方が優先順位が高いため,「KIHON + (TEATE X 12)」(基本給1カ月分と手当て12カ月分)を計算したことになる。正しいSQL文のWHERE句は,
WHERE (KIHON + TEATE) * 12 > 3000000
である。このようなミスは汎用プログラミング言語でも起こり得るが,1行が長くなりがちなSQLでは見落としやすい。

 図5(2)は,論理演算の優先順位を間違えた例である。「基本給が20万円台ではなく,手当てを5万円以上もらっている社員」を検索するのに,

SELECT SYAIN_NO, SYAIN_MEI
FROM SYAIN_TBL
WHERE KIHON < 200000 OR
KIHON >= 300000 AND
TEATE >= 50000 ;
としてしまった。ORとANDでは,ANDの方が優先されるため,「KIHON < 200000 OR (KIHON >= 300000 AND TEATE >= 50000)」((1)基本給が20万円以上,または,(2)基本給が30万円以上かつ手当てが5万円以上)を計算したことになる。正しいSQL文のWHERE句は,
WHERE (KIHON < 200000 OR
KIHON >= 300000) AND
TEATE >= 50000
としなければならない。迷った場合は,カッコを付けよう。
句ごとの改行,字下げ,コメントで読みやすく

 このようなミスを防ぐためには,1行が長くなりがちなSQL文を,できるだけ読みやすくしておくことが大切である。実際のアプリケーション開発においても,複雑なSQL文であるほど,メンテナンス時に何をやっているSQL文なのかを思い出すのに時間が掛かるといったことがよくある。第三者が見ても分かりやすいSQL文を書くように心掛けたい。

 SQL文を読みやすくする基本は,改行や字下げ,コメントを適切に使うことである(図6[拡大表示])。

 まず,SQL文はFROM句やWHERE句などの複数の句から成り立つので,各句ごとに改行する。

SELECT BUMON_MEI FROM BUMON_TBL
と書くのではなく,
SELECT BUMON_MEI
FROM BUMON_TBL
と書く。また,条件を記述するWHERE句などは長くなりやすいので,その場合は,適当に改行して字下げを行う。
WHERE (KIHON < 200000 OR KIHON >= 300000) AND TEATE >= 50000
では読みにくいので,
WHERE (KIHON < 200000 OR
KIHON >= 300000) AND
TEATE >= 50000
とする。

 テーブルの別名を利用すれば,SQL文の長さを短くすることができる。具体的には,

SELECT BUMON_MEI,SYAIN_MEI
FROM SYAIN_TBL S,BUMON_TBL B
WHERE S.BUMON_CD = 10
AND S.BUMON_CD = B.BUMON_CD ;
における,「S」と「B」が別名だ。「S」は実際は「SYAIN_TBL」のことであり,「B」は「BUMON_TBL」のことである。

 SQL文にはコメントをつけることが可能である。SQL文の中に,処理の概要や目的,用途などを日本語で記述できる。SQL文のコメントは,「/*」と「*/」で囲むか,「--」を使う。「--」の場合は,行末までをコメントとみなす。

オブジェクト名の日本語使用は控える

 日本語を使用するとSQL文は読みやすくなるが,テーブル名などに日本語を使用するのはできるだけ避けたい。

 Oracleに限らず,主要なRDBMSでは,テーブル名などのオブジェクト名に日本語などのマルチバイト・コードが利用できる。分かりやすさの観点からは日本語の利用は優れているが,OSや利用するツールなどでマルチバイト・コードが使えない場合が考えられるため,利用は控えたい。例えばデータベースの障害が発生して復旧する場合,サーバーOSにログインしてRDBMSにアクセスし,エクスポートやインポートを行おうとしても,そのOSでマルチバイト・コードが使えなければデータベース・オブジェクトを指定することができない。また,データベースからのメッセージ出力などもマルチバイト・コードでは化けてしまうことが考えられる。

 どうしても日本語名を使いたければ,シノニムビューを使えばよい。テーブルなどは英数字で定義し,その別名としてシノニムを定義してシノニムに日本語名をつける。そうすれば,英数字の名前でも,日本語の名前でもアクセスできるようになる。

(3)検索結果の順番にまつわるミス
  指定しない限り,順番は不定

 RDBMSのレコードの順番には注意が必要だ。テスト環境などでわずか数行のテーブルしかない場合,検索結果のレコードの順番は毎回同じになるだろう。しかし実際は,SELECT文の検索結果のレコードの順番は,指定しない限り不定である(図7[拡大表示])。例えば,

SELECT BUMON_CD, BUMON_MEI
FROM BUMON_TBL ;
というSQL文の結果は,たまたま
BUMON_CD BUMON_MEI
10 AAA
20 BBB
30 CCC
になるかもしれないが,
30 CCC
10 AAA
20 BBB
になることだってあり得る。BUMON_CDの順番で必ず出力させたい場合は,
SELECT BUMON_CD, BUMON_MEI
FROM BUMON_TBL
ORDER BY BUMON_CD ;
とし,ORDER BY句をつける。

 ただし,意味も無いのに並び順を指定してはいけない。レコードの並べ替えは負荷の高い処理なので,必要な場合にのみ指定する。

 ソートにおいて注意したいのは,文字列カラムをソート・カラムに指定した場合だ(図8[拡大表示])。例えば,

SELECT SYAIN_MEI, ADDR
FROM SYAIN_TBL
ORDER BY ADDR ;
とした場合,住所の順番で結果を出力するが,その際の順番は文字コードの順番となるので気を付けたい。

 また,文字列の中に数字が混じっている場合,直観的な順番と異なる順になることがある。先ほどの例では,

えええ XXX10丁目
あああ XXX1丁目
いいい XXX2丁目
ううう XXX3丁目
おおお XXX4丁目
と出力される。しかし人が見た場合,
あああ XXX1丁目
いいい XXX2丁目
ううう XXX3丁目
おおお XXX4丁目
えええ XXX10丁目
と並んだ方がきれいである。このような場合,ストアド・ファンクションを作るなどの方法で,ある程度回避することができる。

 住所の「丁目」の前まで読み,ソートし,その後の丁目の数字文字列の部分を数値に変換してソートする。実際には住所は結構複雑なので簡単ではないが,ある程度見やすい並びにすることができる。

◇      ◇      ◇

 次回は文字列やSQLの関数に焦点をあてて,注意点を解説する予定である。


玉川 敏一(たまがわ としいち)
シーズ・ラボ ITソリューション部 セクションマネージャー

1980年代後半からリレーショナル・データベースを利用している。当初は汎用機上のRDBMSであったが,1994年(株)シーズ・ラボ入社以来,Oracle一筋になる。同社にてシステム開発,研修インストラクタ,サポート窓口,技術支援業務を行い,Oracleと深くかかわっている。Oracle Master Platinum資格を保有。