この動作は直感的ではありませんが、Microsoftのナレッジベースで非常に明確に定義されています。
KB#298674:PRB:サブクエリは列の名前を外部テーブルに解決します
その記事から:
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)
人々は何年もの間この問題について不平を言ってきました、しかしマイクロソフトはそれを修正するつもりはありません。結局のところ、それは本質的に次のように述べている標準に準拠しています。
次のConnectの「バグ」の詳細と、この動作は仕様によるものであり、変更されないことを示す複数の公式確認があります(したがって、変更する必要があります。つまり、常にエイリアスを使用します ):
接続#338468:サブクエリのCTE列名解決が検証されていません
接続#735178:IN演算子を使用するとT-SQLサブクエリが機能しない場合があります
接続#302281:列が存在しないため、サブクエリが無視されます
接続#772612:IN演算子内でエイリアスエラーが報告されない
接続#265772:サブを使用したバグ選択
あなたの場合、ID、OID、PIDよりも意味のある名前を使用すると、この「エラー」が発生する可能性ははるかに低くなります。 Order.PID
を実行します Person.id
をポイントします またはPerson.PID
?人々があなたに尋ねることなく関係を理解できるようにあなたのテーブルをデザインしてください。 PersonID
常にPersonID
である必要があります 、スキーマのどこにあっても、 OrderID
と同じ 。タイピングの数文字を節約することは、完全にあいまいなスキーマにお金を払うのに良い代償ではありません。
EXISTS
を書くことができます 代わりに句:
... 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?
);