Это утверждение является законным (другими словами, нет 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
. Смотрите этот пост для получения дополнительной информации .