To zachowanie, choć nieintuicyjne, jest bardzo dobrze zdefiniowane w Bazie wiedzy Microsoftu:
KB #298674 :PRB:Podzapytanie rozwiązuje nazwy kolumn na zewnętrzne tabele
Z tego artykułu:
CREATE TABLE X1 (ColA INT, ColB INT)
CREATE TABLE X2 (ColC INT, ColD INT)
SELECT ColA FROM X1 WHERE ColA IN (Select ColB FROM X2)
SELECT ColA FROM X1 WHERE ColA in (Select X2.ColB FROM X2)
Ludzie od lat narzekają na ten problem, ale Microsoft nie zamierza tego naprawić. Jest to przecież zgodne ze standardem, który zasadniczo stwierdza:
Więcej informacji w poniższych „błędach” Connect oraz wiele oficjalnych potwierdzeń, że to zachowanie jest zgodne z projektem i nie zmieni się (więc będziesz musiał zmienić swoje – tj. zawsze używaj aliasów ):
Połącz #338468:Rozpoznawanie nazwy kolumny CTE w podzapytaniu nie jest zweryfikowane
Connect #735178 :Podzapytanie T-SQL nie działa w niektórych przypadkach, gdy używany jest operator IN
Połącz #302281 :Nieistniejąca kolumna powoduje ignorowanie podzapytania
Połącz #772612:błąd aliasu nie jest zgłaszany w przypadku operatora IN
Połącz #265772 :Błąd przy użyciu sub wybierz
W twoim przypadku ten "błąd" będzie prawdopodobnie znacznie mniej prawdopodobny, jeśli użyjesz bardziej znaczących nazw niż ID, OID i PID. Czy Order.PID
? wskaż Person.id
lub Person.PID
? Zaprojektuj swoje stoły tak, aby ludzie mogli rozgryźć relacje bez pytania. PersonID
powinien zawsze być PersonID
, bez względu na to, gdzie to jest w schemacie; to samo z OrderID
. Zapisanie kilku znaków pisania nie jest dobrą ceną za całkowicie niejednoznaczny schemat.
Możesz napisać EXISTS
zamiast tego klauzula:
... FROM dbo.Person AS p WHERE EXISTS
(
SELECT 1 FROM dbo.[Order] AS o
WHERE o.PID = p.id -- or is it PID? See why it pays to be explicit?
);