Hành vi này, mặc dù không trực quan, nhưng được xác định rất rõ trong Cơ sở Kiến thức của Microsoft:
KB # 298674:PRB:Truy vấn con thay đổi tên của cột thành bảng bên ngoài
Từ bài báo đó:
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)
Nhiều người đã phàn nàn về vấn đề này trong nhiều năm, nhưng Microsoft sẽ không sửa chữa nó. Xét cho cùng, nó tuân thủ tiêu chuẩn, về cơ bản nêu rõ:
Thông tin thêm trong "lỗi" Connect sau cùng với nhiều xác nhận chính thức rằng hành vi này là do thiết kế và sẽ không thay đổi (vì vậy bạn sẽ phải thay đổi bí danh của mình - tức là luôn sử dụng bí danh ):
Kết nối # 338468:Độ phân giải Tên Cột CTE trong Truy vấn Phụ không được xác thực
Connect # 735178:Truy vấn con T-SQL không hoạt động trong một số trường hợp khi toán tử IN được sử dụng
Kết nối # 302281:Cột không tồn tại khiến truy vấn con bị bỏ qua
Connect # 772612:Lỗi bí danh không được báo cáo khi ở trong toán tử IN
Connect # 265772:Lỗi khi sử dụng phụ chọn
Trong trường hợp của bạn, "lỗi" này có lẽ sẽ ít xảy ra hơn nhiều nếu bạn sử dụng nhiều tên có ý nghĩa hơn ID, OID và PID. Có Order.PID
trỏ tới Person.id
hoặc Person.PID
? Thiết kế bảng của bạn để mọi người có thể tìm ra các mối quan hệ mà không cần phải hỏi bạn. Một PersonID
phải luôn là PersonID
, bất kể nó nằm ở đâu trong lược đồ; giống với OrderID
. Tiết kiệm một vài ký tự khi nhập không phải là một cái giá tốt để trả cho một lược đồ hoàn toàn mơ hồ.
Bạn có thể viết một EXISTS
mệnh đề thay thế:
... 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?
);