- 7.1. サブクエリの基本
- 7.2. WHERE 句でのサブクエリ
- 7.3. HAVING 句でのサブクエリ
- 7.4. その他の場所でのサブクエリ
- 7.5. 相関サブクエリ
- 7.6. EXISTS, ANY, ALL
7.6. EXISTS, ANY, ALL
演算子 EXISTS, ANY, ALL はサブクエリが返す値に対して、「TRUE」または「FALSE」の評価を行い、メインクエリの WHERE 句で使用されます。サブクエリの返す値の集合を結果セットと呼びます。EXISTS 演算子は結果セットの有無を評価します。ANY 演算子は結果セットのいずれかの値を評価対象とします。ALL 演算子は結果セットの全ての値を評価対象とします。
7.6.1. EXISTS
EXIST 演算子はサブクエリの生成した値が存在する場合は「TRUE」、存在しない場合は「FALSE」を返します。ANY 演算子、ALL 演算子は「=」「<」等の比較演算子と共に用いて、全体で「TRUE」または「FALSE」の評価をしますが、EXISTS 演算子だけは単独で「TRUE」または「FALSE」の評価を行います。また、サブクエリの返す値は複数の行のものでも、複数の列のものでも構いません。
-- sample.19-1 --/* EXISTS */ SELECT * FROM 商品表 WHERE EXISTS (SELECT * FROM 商品表 WHERE 商品名 = 'BEER');
実行結果
商品コード 商品名 単価 ───────── ───── ──── 101 BEER 500 102 JUICE 400 103 TEA 400 104 WINE 650
sample.19-1 のクエリは、サブクエリで商品表から商品名が 'BEER' と一致するものを出力し、値が出力されれば、商品表の全てを表示するというものです。商品表には商品名が 'BEER' というものがありますので、商品表の全てが参照されます。sample.19-1 のように、EXISTS にはいくつの列が返されても構いません。
相関サブクエリについても EXISTS を使用することが出来ます。sample.19-2 では、受注表から'JUICE'を受注した受注番号と顧客コードを参照します。相関サブクエリでは、メインクエリから受け取った各行ごとに EXISTS 演算子は「TRUE」か「FALSE」の評価を行います。
-- sample.19-2 --/* EXISTS */ SELECT 受注番号,顧客コード FROM 受注表 JJ WHERE EXISTS (SELECT * FROM 商品表 SS WHERE 商品名 = 'JUICE' AND JJ.商品コード = SS.商品コード);
実行結果
受注番号 顧客コード ─────── ───────── 10001 001 10004 004 10007 003
sample.19-2 では、まず受注表から受注番号が '10001' である行をサブクエリで使用します。この行の商品コードを商品表の商品コードと比較します。また同時にその商品名が 'JUICE' であるかもチェックしています。この行の商品コードは '102' で、同時に商品表の商品名は 'JUICE' となります。この行と商品表の各行の比較が終わったとき、サブクエリは商品表の商品名が 'JUICE' の行について、全ての列の値を出力します。EXISTS 演算子はこれを受け取って「TRUE」と評価します。そして受注番号が '10001' の行は出力されることが決まり、受注番号と顧客コードが表示されるということになります。そして同じことが受注表の全ての行に対して行われ、結局 'JUICE' を注文したときの行についてのみ出力されることにな ります。
通常のサブクエリでは、EXISTS 演算子は結果の存在有無を一度しか評価しませんが、相関サブクエリではそれぞれの行に対して評価を行います。
EXISTS 演算子には、NOT EXISTS と記述することで EXISTS 演算子と反対の役割を果たすようになります。すなわち、サブクエリの値が存在するときは「FALSE」、存在しないときは「TRUE」と評価します。
7.6.2. ANY
ANY 演算子はサブクエリの生成した値のいずれかの値を評価対象とします。ANY 演算子は比較演算子と共に用いられ、結果セットの値のいずれかが比較演算子の関係を満たす場合に「TRUE」、満たさなければ「FALSE」を返します。また、サブクエリが生成する値は複数でも構いません。
次の図はメインクエリの WHERE 句の述語を表しています。サブクエリから生成された値の集合である結果セット [value A, value B, value C, ...] でいずれかが、[列名] の値と比較して比較演算子との関係を満たせば、「TRUE」を返します。満たさない場合はもちろん「FALSE」を返します。
([列名] + 比較演算子 + value A) OR ([列名] + 比較演算子 + value B) OR ([列名] + 比較演算子 + value C) ... というようなイメージです。
sample.19-3 では、受注表において納品日が顧客コードが '002' のものと同じであるものを参照します。
-- sample.19-3 --/* ANY */ SELECT 顧客コード,納品日 FROM 受注表 WHERE 納品日 = ANY (SELECT 納品日 FROM 受注表 WHERE 顧客コード = '002');
実行結果
顧客コード 納品日 ───────── ───── 001 20010401 002 20010401 004 20010402 002 20010402 001 20010402 003 20010402
サブクエリでは、顧客コードが '002' の納品日を出力します。納品日が [20010401, 20010402] という結果セットが作られます。この結果セットの中のいずれかについてメインクエリの WHERE 句で「TRUE」になるものについて、顧客コードと納品日が出力されます。これは、前に説明した IN を用いた場合と同じ効果が得られます。sample.19-4 は IN を使用して、sample.19-3 と同じ出力を得るものです。
-- sample.19-4 --/* IN */ SELECT 顧客コード,納品日 FROM 受注表 WHERE 納品日 IN (SELECT 納品日 FROM 受注表 WHERE 顧客コード = '002');
実行結果
顧客コード 納品日 ───────── ───── 001 20010401 002 20010401 004 20010402 002 20010402 001 20010402 003 20010402
しかし、ANY 演算子は IN 演算子では出来なかったことが出来るようになっています。ANY 演算子は比較演算子として、「=」だけでなく「>」「<=」などの不等号も使用できるのです。sample.19-5 では受注表において、受注個数が顧客コード '004' の受注個数の最大よりも小さなものについて、参照します。
-- sample.19-5 --/* ANY */ SELECT 受注番号,顧客コード,受注個数 FROM 受注表 WHERE 受注個数 < ANY (SELECT 受注個数 FROM 受注表 WHERE 顧客コード = '004');
実行結果
受注番号 顧客コード 受注個数 ─────── ───────── ─────── 10003 004 150 10004 004 80 10005 002 110 10007 003 45 10008 004 135 10009 003 65 10011 003 60
sample.19-5 ではサブクエリで受注表から顧客コードが '004' のものについて、受注個数を出力しています。この結果セットは [80, 135, 150, 175] です。これらの値のうちいずれかについて、受注表の各行の受注個数が小さくなる行が出力されます。受注個数が 175 未満であるものについて出力されることになります。
また ANY 演算子と全く同じ機能を持つ演算子があります。SOME 演算子を用いることにより、ANY 演算子と同じ効果が得られます。
7.6.3. ALL
ALL 演算子はサブクエリの生成した値の全てを評価対象とします。ANY 演算子と同じように、ALL 演算子も比較演算子と共に用いられます。結果セットの値の全てが比較演算子との関係を満たす場合に「TRUE」、満たさなければ「FALSE」を返します。また、ANY 演算子と同様に、サブクエリが生成する値は複数でも構いません。
先ほどの図とほぼ変わりありませんが、次の図で言うと、結果セット [value A, value B, value C, ...] の全てが、[列名] の値と比較して比較演算子との関係を満す時「TRUE」を返します。満たさない場合は「FALSE」を返します。
([列名] + 比較演算子 + value A) AND ([列名] + 比較演算子 + value B) AND ([列名] + 比較演算子 + value C) ... というようなイメージです。
sample.19-6 は、sample.19-5 の ANY を ALL に変えただけです。受注表から受注個数が顧客コード '004' の受注個数の最小値より小さなものについて、受注番号、顧客コード及び受注個数を参照します。
-- sample.19-6 --/* ALL */ SELECT 受注番号,顧客コード,受注個数 FROM 受注表 WHERE 受注個数 < ALL (SELECT 受注個数 FROM 受注表 WHERE 顧客コード = '004');
実行結果
受注番号 顧客コード 受注個数 ─────── ───────── ───────── 10007 003 45 10009 003 65 10011 003 60
sample.19-6 ではサブクエリで受注表から顧客コードが '004' のものについて、受注個数を出力しています。この結果セットは [80, 135, 150, 175] です。これらの値のうち全てについて、受注表の各行の受注個数が小さくなる行が出力されます。受注個数が 80 未満であるものについて出力されることになります。