Tuyên bố này là hợp pháp (nói cách khác, không FROM
bắt buộc):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
Bí quyết là khi bạn giới thiệu một tên cột rõ ràng không thể tồn tại. Vì vậy, những thất bại:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Msg 207, Cấp 16, Bang 1
Tên cột 'không hợp lệ'.
Msg 207, Cấp 16, Trạng thái 1
Tên cột không hợp lệ 'id'.
Nhưng khi cột không hợp lệ được giới thiệu trong một cái gì đó giống như truy vấn con, SQL Server sẽ làm gì khi không thể tìm thấy cột đó trong phạm vi bên trong của truy vấn con, đi qua phạm vi bên ngoài và làm cho truy vấn con tương quan với phạm vi bên ngoài đó. Điều này sẽ trả về tất cả các hàng, ví dụ:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Bởi vì về cơ bản nó nói:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Bạn thậm chí không cần một WHERE
mệnh đề trong truy vấn con:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Bạn có thể thấy rằng nó thực sự nhìn vào bảng có phạm vi bên ngoài, bởi vì điều này:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Trả về hàng ít hơn nhiều (11 trên hệ thống của tôi).
Điều này liên quan đến việc tuân thủ các tiêu chuẩn về phạm vi. Bạn có thể thấy những điều tương tự khi bạn có hai bảng #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
Rõ ràng, điều này nên lỗi, phải, vì không có foo
trong #bar
? Không. Điều xảy ra là SQL Server nói, "ồ, tôi không tìm thấy foo
ở đây, bạn phải có ý nghĩa khác."
Ngoài ra, nói chung, tôi sẽ tránh NOT IN
. NOT EXISTS
có khả năng hiệu quả hơn trong một số tình huống, nhưng quan trọng hơn, hành vi của nó không thay đổi khi có thể cột mục tiêu có thể NULL
. Xem bài đăng này để biết thêm .