ひとり勉強ログ

ITエンジニアの勉強したことメモ

MySQL講座#04 論理演算子

NOT演算子

「~ではない」という否定の条件を指定するのに<>演算子を使うと説明したが、同じ否定でも、もう少し広く使える演算子としてNOTがある。

NOTは単独では使用しない。他の検索条件と組み合わせて使用する。例えば、「超人強度(power)が4000以上」の行を選択するSELECT文は以下でした。

[sql] SELECT name, category, power FROM chojin WHERE power >= 4000; [/sql]

結果

[sql] +--------------------------------+--------------+-------+ | name | category | power | +--------------------------------+--------------+-------+ | マックス・ラジアル | 完璧超人 | 4800 | | ターボメン | 完璧超人 | 4000 | | ピークア・ブー | 完璧超人 | 4200 | | ストロング・ザ・武道 | 完璧超人 | 9999 | | ネメシス | 完璧超人 | 6800 | | ポーラマン | 完璧超人 | 7200 | +--------------------------------+--------------+-------+ [/sql]

このSELECT文の検索条件にNOT演算子を追加すると、次のようになる。

[sql] SELECT name, category, power FROM chojin WHERE NOT power >= 4000; [/sql]

結果

[sql] +-----------------------------+--------------+-------+ | name | category | power | +-----------------------------+--------------+-------+ | キン肉マン | 正義超人 | 95 | | テリーマン | 正義超人 | 95 | | ロビンマスク | 正義超人 | 96 | | ウォーズマン | 正義超人 | 100 | | ラーメンマン | 正義超人 | 97 | | ブロッケンJr | 正義超人 | 90 | | ウルフマン | 正義超人 | 80 | | ステカセキング | 悪魔超人 | 250 | | ブラックホール | 悪魔超人 | 200 | | ミスター・カーメン | 悪魔超人 | 200 | | ザ・魔雲天 | 悪魔超人 | 50 | 以下省略 [/sql]

超人強度が4000以上(power >= 4000)という条件が否定されて、powerが4000未満の超人が選択されている。すなわち、上記の検索条件は次の検索条件(WHERE power < 4000)と同値。

[sql] SELECT name, category, power FROM chojin WHERE power < 4000; [/sql]

この例からも明らかなように、NOT演算子を使用しなくても同じ検索条件を記述することは可能。それどころか、NOT演算子を使わないほうが分かりやすく記述できる。

かといって、NOT演算子がまったく不要な訳ではない。

AND演算子とOR演算子

SELECT文で複数の検索条件で選択する行を絞り込みたいケースがよくある。例えば、「」などである。

WHERE句ではAND演算子やOR演算子を使って、複数の検索条件を組み合わせることができる。

AND演算子は「両辺の検索条件が両方とも成り立つときに、全体の条件として成り立つ」という働きがある。日本語で表現すると「かつ」に相当する。

OR演算子は、「両辺の検索条件のうち、どちらか一方あるいは両方が成り立つときに全体の検索条件として成り立つ」という働きがある。日本語で表現すると「または」に相当する。

例えば、chojinテーブルから「categoryが完璧超人(category = '完璧超人')で、かつ超人強度が5000以上(power >= 5000)の超人」を選択する検索条件を表すには、AND演算子を使用する。

[sql] SELECT name, category, power FROM chojin WHERE category = '完璧超人' AND power >= 5000; [/sql]

結果

[sql] +--------------------------------+--------------+-------+ | name | category | power | +--------------------------------+--------------+-------+ | ストロング・ザ・武道 | 完璧超人 | 9999 | | ネメシス | 完璧超人 | 6800 | | ポーラマン | 完璧超人 | 7200 | +--------------------------------+--------------+-------+ [/sql]

一方、「categoryが悪魔超人(category = '悪魔超人')、または身長が250以上(height >= 250)の超人」を選択する検索条件を表すには、OR演算子を使用する。

[sql] SELECT name, category, height FROM chojin WHERE category = '悪魔超人' OR height >= 250; [/sql]

結果

[sql] +--------------------------------+--------------+--------+ | name | category | height | +--------------------------------+--------------+--------+ | ステカセキング | 悪魔超人 | 214 | | ブラックホール | 悪魔超人 | 201 | | ミスター・カーメン | 悪魔超人 | 200 | | ザ・魔雲天 | 悪魔超人 | 285 | | アトランティス | 悪魔超人 | 200 | | スプリングマン | 悪魔超人 | 104 | | バッファローマン | 悪魔超人 | 250 | | スニゲーター | 悪魔超人 | 210 | | プラネットマン | 悪魔超人 | 254 | | ジャンクマン | 悪魔超人 | 190 | | ザ・ニンジャ | 悪魔超人 | 190 | | アシュラマン | 悪魔超人 | 203 | | サンシャイン | 悪魔超人 | 300 | | マックス・ラジアル | 完璧超人 | 256 | | クラッシュマン | 完璧超人 | 283 | | ストロング・ザ・武道 | 完璧超人 | 290 | | ポーラマン | 完璧超人 | 278 | | ミラージュマン | 完璧超人 | 263 | | ガンマン | 完璧超人 | 302 | | シングマン | 完璧超人 | 298 | | カラスマン | 完璧超人 | 260 | +--------------------------------+--------------+--------+ [/sql]

カッコ()を付けると強くなる

例えば、次のような検索条件でchojinテーブルを検索するSELECT文では、WHERE句にどのような条件を書けば良いだろうか。

「categoryが悪魔超人」
かつ
「身長が200または250」

この検索条件に合う超人は「ミスター・カーメン」と「アトランティス」のみ。この検索条件をそのままWHERE句に書くと、以下のSELECT文ができあがる。

[sql] SELECT name, category, height FROM chojin WHERE category = '悪魔超人' AND height = '200' OR height = '220'; [/sql]

結果

[sql] +-----------------------------+--------------+--------+ | name | category | height | +-----------------------------+--------------+--------+ | ミスター・カーメン | 悪魔超人 | 200 | | アトランティス | 悪魔超人 | 200 | | ゴールドマン | 完璧超人 | 220 | | シルバーマン | 完璧超人 | 220 | +-----------------------------+--------------+--------+ [/sql]

不要な「ゴールドマン」「シルバーマン」まで結果に含まれている。理由はOR演算子よりAND演算子の方が優先されるからである。したがって、この条件式は

「category = '悪魔超人' AND height = '200'」
OR
「height = '220'」

と解釈される。つまり、

「categoryが悪魔超人である、かつ、身長が200である」
または
「身長が220である」

ということで、指定したかった検索条件とは違ってしまう。AND演算子よりもOR演算子を優先したいときは、以下のようにOR演算子とその両辺を半角文字のカッコ()で囲む。

[sql] SELECT name, category, height FROM chojin WHERE category = '悪魔超人' AND (height = '200' OR height = '220'); [/sql]

結果

[sql] +-----------------------------+--------------+--------+ | name | category | height | +-----------------------------+--------------+--------+ | ミスター・カーメン | 悪魔超人 | 200 | | アトランティス | 悪魔超人 | 200 | +-----------------------------+--------------+--------+ [/sql]

論理演算子と真理値

NOT、AND、ORの3つの演算子は論理演算子と呼ばれる。ここでいう論理とは「真理値を操作する」という意味。真理値とは、真(TRUE)または偽(FALSE)のいずれかの値のことである。

比較演算子は、演算の結果として真理値を返す。比較した結果が成り立てば真(TRUE)、成り立たなければ(FALSE)。例えば、power >= 5000 という検索条件についてname列が'ネメシス'の行ではpower列が6800なので真(TRUE)を返し、name列が'グリムリパー'の行ではpower列が1000なので偽(FALSE)を返す。

論理演算子は、比較演算子などが返した真理値を操作する。AND演算子は両辺の真理値がともに真であるときに真、それ以外は偽を返す。OR演算子は両辺がともに偽でなければ真、両辺が偽のときだけ偽を返す。NOT演算子は単純に、真を偽に、偽を真に反転させる。

SELECT分のWHERE句に、AND演算子で2つの検索条件を組み合わせた条件式を指定した場合には、両辺の検索条件がともに真となる行が選択される。OR演算子で2つの検索条件を組み合わせた条件式を指定した場合には、両辺の検索条件のどちらか一方あるいは両方が真になるまで行が選択される。条件式にNOT演算子を使った場合には、続く検索条件が偽である行(反転して真になる)が選択される。

2つ以上の論理演算子を使って3つ以上の検索条件を組み合わせている場合も、論理演算を繰り返して真理値を求めていけば、どれだけ複雑な条件でも機械的に結果を得ることができる。

次の表は、例に挙げた「category = '悪魔超人' AND (height = '200' OR height = '220')」という検索条件について作成した真理表である。

PQRQ OR RP AND (Q OR R)

NULLを含む場合の真理値

比較演算子(=や<>)ではNULLを検索できず、IS NULL演算子やIS NOT NULL演算子を使う必要がある。実は、論理演算子でもNULLを特別視しなければならない。

chojinテーブルでは、name「スペシャルマン」と「カナディアンマン」のattributeはNULLである。では、これらの行をattribute = 'アイドル超人'という条件式に照らしたときの真理値は何になるだろうか。もし真ならば、この条件式をWHERE句に指定することで「スペシャルマン」と「カナディアンマン」の行を選択できる。しかし、「NULLに比較演算子は使えない」で見たようにそうはならない。したがって真ではない。

では、偽だろうか。実は、偽でもない。もし偽になるなら、この条件を否定したNOT attribute = 'アイドル超人'(attributeがアイドル超人ではない)という条件のとき真となり、これらの行が選択されるはずだからである。ところが、実際にはそうならない。

真でも偽でもないと何になるのか。ここがSQLの落とし穴。この場合の真理値は「不明(UNKNOWN)」という第三の値になる。普通の論理演算には、この3つ目の値は存在しない。SQL以外の言語においても、ほとんどは真と偽の2つだけの真理値を使う。通常の論理演算が2値論理と呼ばれるのに対し、SQLだけは3値論理と呼ばれる。