ここでの回答から、NOT IN (subquery)
ヌルを正しく処理しないと結論付けられる可能性があり、NOT EXISTS
. しかし、そのような結論は時期尚早かもしれません。次のシナリオでは、Chris Date (Database Programming and Design、Vol 2 No 9、1989 年 9 月) の功績により、NOT IN
null を正しく処理し、正しい結果を返しますNOT EXISTS
。
数量 ( ) の部品 ( ) を供給することが知られているsp
サプライヤ ( ) を表すテーブルを考えてみましょう。現在、テーブルには次の値が保持されています。sno
pno
qty
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
数量はヌル可能であることに注意してください。つまり、サプライヤが部品を供給することが知られているという事実を、数量が不明であっても記録できるようにするためです。
このタスクは、供給部品番号 'P1' が知られているが、数量が 1000 ではない供給業者を見つけることです。
以下はNOT IN
、サプライヤ 'S2' のみを正しく識別するために使用されます。
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND 1000 NOT IN (
SELECT spy.qty
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
);
ただし、以下のクエリは同じ一般的な構造を使用していますがNOT EXISTS
、結果にサプライヤ 'S1' が誤って含まれています (つまり、数量が null です)。
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1', NULL ),
( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT DISTINCT spx.sno
FROM sp spx
WHERE spx.pno = 'P1'
AND NOT EXISTS (
SELECT *
FROM sp spy
WHERE spy.sno = spx.sno
AND spy.pno = 'P1'
AND spy.qty = 1000
);
だからNOT EXISTS
、それが現れたかもしれない特効薬ではありません!
もちろん、問題の原因は null の存在にあるため、「実際の」解決策はこれらの null を削除することです。
これは、2 つのテーブルを使用して (他の可能な設計の中でも) 実現できます。
sp
部品供給で知られるサプライヤー
spq
既知の数量の部品を供給することが知られているサプライヤー
spq
おそらく参照先に外部キー制約があるはずであることに注意してくださいsp
。
EXCEPT
次に、「マイナス」関係演算子 (標準 SQL のキーワード)を使用して結果を取得できます。
WITH sp AS
( SELECT *
FROM ( VALUES ( 'S1', 'P1' ),
( 'S2', 'P1' ),
( 'S3', 'P1' ) )
AS T ( sno, pno )
),
spq AS
( SELECT *
FROM ( VALUES ( 'S2', 'P1', 200 ),
( 'S3', 'P1', 1000 ) )
AS T ( sno, pno, qty )
)
SELECT sno
FROM spq
WHERE pno = 'P1'
EXCEPT
SELECT sno
FROM spq
WHERE pno = 'P1'
AND qty = 1000;