Это утверждение является законным (другими словами, нет 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
. Смотрите этот пост для получения дополнительной информации .
Я воспроизвел это в 2016 году на упрощенном примере:
Похоже, что c2 и c3 оцениваются для каждой строки.
источник
В SQL Server синтаксис SELECT не требует раздела FROM. Если вы опустите FROM, оператор select будет использовать «фиктивную» таблицу, которая имеет одну строку и не содержит столбцов. Так
вернет одну строку, если выражение истинно, и не будет строк, если оно ложно.
источник
select c
иc
не существует в каком-то внешнем объекте. Я согласен, чтоFROM
это не обязательно, но механика, которая используется здесь, когда вы явно указываете столбец, который существует во внешней области видимости, определенно отличается от фиктивной таблицы, и если вы не предоставляете константу для столбца, который не Если вы существуете, вы получаете ошибку во время выполнения, поэтому там нет и фиктивной таблицы. Фиктивная таблица может вступать в игру в других сценариях, но не тогда, когда ссылка находится в подзапросе / производной таблице.SELECT 'x' AS c
- это совершенно другой сценарий, чем у ОП, который только что сказалSELECT c
. В подзапросе / производной таблице.