Dapat disimpulkan dari jawaban di sini yang NOT IN (subquery)
tidak menangani nulls dengan benar dan harus dihindari NOT EXISTS
. Namun, kesimpulan seperti itu mungkin prematur. Dalam skenario berikut, dikreditkan ke Chris Date (Pemrograman dan Desain Basis Data, Vol 2 No 9, September 1989), itu NOT IN
yang menangani nulls dengan benar dan mengembalikan hasil yang benar, daripada NOT EXISTS
.
Pertimbangkan tabel sp
untuk mewakili pemasok ( sno
) yang dikenal memasok bagian ( pno
) dalam jumlah ( qty
). Tabel saat ini memuat nilai-nilai berikut:
VALUES ('S1', 'P1', NULL),
('S2', 'P1', 200),
('S3', 'P1', 1000)
Perhatikan bahwa kuantitas dapat dibatalkan yaitu untuk dapat mencatat fakta bahwa pemasok diketahui memasok suku cadang meskipun tidak diketahui dalam jumlah berapa.
Tugasnya adalah menemukan pemasok yang dikenal sebagai nomor bagian persediaan 'P1' tetapi tidak dalam jumlah 1000.
Penggunaan berikut NOT IN
untuk mengidentifikasi dengan benar pemasok 'S2' saja:
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'
);
Namun, kueri di bawah ini menggunakan struktur umum yang sama tetapi dengan NOT EXISTS
tetapi salah memasukkan pemasok 'S1' dalam hasilnya (yaitu yang kuantitasnya nol):
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
);
Jadi NOT EXISTS
bukan peluru perak yang mungkin muncul!
Tentu saja, sumber masalahnya adalah keberadaan nulls, oleh karena itu solusi 'nyata' adalah untuk menghilangkan nulls tersebut.
Ini dapat dicapai (di antara kemungkinan desain lainnya) menggunakan dua tabel:
sp
pemasok yang diketahui memasok suku cadang
spq
pemasok diketahui memasok suku cadang dalam jumlah yang dikenal
mencatat mungkin harus ada batasan kunci asing di mana spq
referensi sp
.
Hasilnya kemudian dapat diperoleh dengan menggunakan operator relasional 'minus' (menjadi EXCEPT
kata kunci dalam SQL Standar) misalnya
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;
NOT IN
serangkaian<> and
perubahan perilaku semantik tidak pada set ini menjadi sesuatu yang lain?