To oświadczenie jest legalne (innymi słowy, nie FROM
jest wymagane):
SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;
Sztuką jest wprowadzenie nazwy kolumny, która najwyraźniej nie może istnieć. Te zawodzą:
SELECT name WHERE 1 = 1;
SELECT x = 1 WHERE id > 0;
Msg 207, poziom 16, stan 1
Niepoprawna nazwa kolumny „nazwa”.
Msg 207, poziom 16, stan 1
Niepoprawna nazwa kolumny „id”.
Ale gdy niepoprawna kolumna zostanie wprowadzona do czegoś w rodzaju podkwerendy, to co SQL Server robi, gdy nie może znaleźć tej kolumny w wewnętrznym zakresie podkwerendy, przechodzi do zakresu zewnętrznego i powoduje, że podkwerenda jest skorelowana z tym zakresem zewnętrznym. Zwróci to wszystkie wiersze, na przykład:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);
Ponieważ zasadniczo mówi:
SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
^^^^^^^^^^^ -----------
| |
----------------------------------- */
Nie potrzebujesz nawet WHERE
klauzuli w podzapytaniu:
SELECT * FROM sys.columns WHERE name IN (SELECT name);
Widać, że naprawdę patrzy na zewnętrzny stół z lunetą, ponieważ to:
SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');
Zwraca znacznie mniej wierszy (11 w moim systemie).
Wymaga to przestrzegania standardu określania zakresu. Możesz zobaczyć podobne rzeczy, gdy masz dwie tabele #temp:
CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);
SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);
Oczywiście, należy ten błąd, w prawo, ponieważ nie jest foo
w #bar
? Nie. To, co się dzieje, to to, że SQL Server mówi: „och, nie znalazłem foo
tutaj, musiałeś mieć na myśli ten drugi”.
Poza tym ogólnie bym unikał NOT IN
. NOT EXISTS
ma potencjał, aby być bardziej wydajnym w niektórych scenariuszach, ale co ważniejsze, jego zachowanie nie zmienia się, gdy możliwe jest, że kolumna docelowa mogłaby być NULL
. Zobacz ten post, aby uzyskać więcej informacji .