Ця заява є законною (іншими словами, не FROM
потрібно):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
Хитрість полягає в тому, коли ви вводите ім'я стовпця, яке явно не може існувати. Отже, ці невдачі:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Повідомлення 207, рівень 16, стан 1
Недійсне ім'я стовпця "ім'я".
Повідомлення 207, рівень 16, стан 1
Недійсна назва стовпця "id".
Але коли недійсний стовпчик вводиться у щось на зразок підзапиту, те, що робить SQL Server, коли він не може знайти цей стовпець у внутрішній області підзапиту, переходить до зовнішньої області, і підзапрос корелює з цією зовнішньою областю. Це поверне всі рядки, наприклад:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Тому що це по суті говорить:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Вам навіть не потрібне WHERE
застереження в підзапиті:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Ви можете бачити, що він дійсно дивиться на зовнішню таблицю обліку, тому що це:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Повертає набагато менше рядків (11 у моїй системі).
Це передбачає дотримання стандарту щодо масштабування. Ви можете бачити подібні речі, коли у вас є дві таблиці #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
Очевидно, це має помилитися, правда, оскільки немає foo
в #bar
? Ні. Що відбувається, так це те, що SQL Server каже: "о, я foo
тут не знайшов , ви, мабуть, мали на увазі іншого".
Також взагалі я б уникав NOT IN
. NOT EXISTS
має потенціал бути ефективнішим у деяких сценаріях, але що важливіше, його поведінка не змінюється, коли можливо, що цільовий стовпець міг би бути NULL
. Дивіться цю публікацію для отримання додаткової інформації .