Questo comportamento, sebbene non intuitivo, è molto ben definito nella Knowledge Base di Microsoft:
KB #298674 :PRB:la sottoquery risolve i nomi delle colonne nelle tabelle esterne
Da quell'articolo:
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)
La gente si lamenta da anni di questo problema, ma Microsoft non lo risolverà. Dopotutto, è conforme allo standard, che essenzialmente afferma:
Maggiori informazioni nei seguenti "bug" di Connect insieme a molteplici conferme ufficiali che questo comportamento è di progettazione e non cambierà (quindi dovrai cambiare il tuo, ad es. usa sempre gli alias ):
Connect #338468:la risoluzione del nome della colonna CTE nella query secondaria non è convalidata
Connect #735178 :la sottoquery T-SQL non funziona in alcuni casi quando viene utilizzato l'operatore IN
Connetti #302281 :la colonna inesistente fa sì che la sottoquery venga ignorata
Connect #772612 :errore alias non segnalato all'interno di un operatore IN
Connect #265772 :Bug using sub seleziona
Nel tuo caso, questo "errore" sarà probabilmente molto meno probabile se utilizzi nomi più significativi di ID, OID e PID. Order.PID
punta a Person.id
o Person.PID
? Progetta i tuoi tavoli in modo che le persone possano capire le relazioni senza doverti chiedere. Un PersonID
dovrebbe essere sempre un PersonID
, non importa dove si trovi nello schema; lo stesso con un OrderID
. Salvare alcuni caratteri durante la digitazione non è un buon prezzo da pagare per uno schema completamente ambiguo.
Potresti scrivere un EXISTS
clausola invece:
... 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?
);