Perilaku ini, meskipun tidak intuitif, didefinisikan dengan sangat baik di Basis Pengetahuan Microsoft:
KB #298674 :PRB:Subquery Menyelesaikan Nama Kolom ke Tabel Luar
Dari artikel itu:
CREATE TABLE X1 (ColA INT, ColB INT)
CREATE TABLE X2 (ColC INT, ColD INT)
SELECT ColA FROM X1 WHERE ColA IN (Select ColB FROM X2)
SELECT ColA FROM X1 WHERE ColA in (Select X2.ColB FROM X2)
Orang-orang telah mengeluh tentang masalah ini selama bertahun-tahun, tetapi Microsoft tidak akan memperbaikinya. Bagaimanapun, ini mematuhi standar, yang pada dasarnya menyatakan:
Informasi lebih lanjut dalam "bug" Connect berikut bersama dengan beberapa konfirmasi resmi bahwa perilaku ini dirancang dan tidak akan berubah (jadi Anda harus mengubah milik Anda - yaitu selalu gunakan alias ):
Connect #338468 :Resolusi Nama Kolom CTE di Sub Query tidak divalidasi
Hubungkan #735178 :Subquery T-SQL tidak berfungsi dalam beberapa kasus saat operator IN digunakan
Hubungkan #302281 :Kolom yang tidak ada menyebabkan subquery diabaikan
Hubungkan #772612 :Kesalahan alias tidak dilaporkan saat berada dalam operator IN
Hubungkan #265772 :Bug menggunakan sub pilih
Dalam kasus Anda, "kesalahan" ini kemungkinan kecil akan terjadi jika Anda menggunakan nama yang lebih bermakna daripada ID, OID, dan PID. Apakah Order.PID
arahkan ke Person.id
atau Person.PID
? Rancang tabel Anda sehingga orang dapat mengetahui hubungannya tanpa harus bertanya kepada Anda. PersonID
harus selalu berupa PersonID
, di mana pun dalam skema itu; sama dengan OrderID
. Menyimpan beberapa karakter pengetikan bukanlah harga yang baik untuk membayar skema yang sepenuhnya ambigu.
Anda dapat menulis EXISTS
klausa sebagai gantinya:
... FROM dbo.Person AS p WHERE EXISTS
(
SELECT 1 FROM dbo.[Order] AS o
WHERE o.PID = p.id -- or is it PID? See why it pays to be explicit?
);