Detta beteende, även om det är ointuitivt, är mycket väl definierat i Microsofts kunskapsbas:
KB #298674 :PRB:Subquery löser namn på kolumner till yttre tabeller
Från den artikeln:
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)
Folk har klagat på det här problemet i flera år, men Microsoft kommer inte att fixa det. Det följer trots allt standarden, som i huvudsak säger:
Mer information i följande Connect-"buggar" tillsammans med flera officiella bekräftelser på att detta beteende är designat och inte kommer att förändras (så du måste ändra ditt - d.v.s. använd alltid alias ):
Anslut #338468 :CTE-kolumnnamnsupplösning i underfrågan är inte validerad
Anslut #735178:T-SQL-underfrågan fungerar inte i vissa fall när IN-operator används
Anslut #302281 :Icke-existerande kolumn gör att underfrågan ignoreras
Anslut #772612:Aliasfel rapporteras inte inom en IN-operatör
Anslut #265772 :Fel med sub välj
I ditt fall kommer detta "fel" förmodligen att uppstå mycket mindre om du använder mer meningsfulla namn än ID, OID och PID. Gör Order.PID
peka på Person.id
eller Person.PID
? Designa dina tabeller så att folk kan ta reda på relationerna utan att behöva fråga dig. Ett PersonID
ska alltid vara ett PersonID
, oavsett var i schemat det är; samma sak med ett OrderID
. Att spara några tecken för att skriva är inte ett bra pris att betala för ett helt tvetydigt schema.
Du kan skriva en EXISTS
klausul istället:
... 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?
);