この動作は、直感的ではありませんが、Microsoft のナレッジ ベースで非常に明確に定義されています。
KB #298674 : PRB: サブクエリが列の名前を外部テーブルに解決する
その記事から:
動作を説明するために、次の 2 つのテーブル構造とクエリを使用します。
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)
クエリは、列 ColB がテーブル X1 から考慮される結果を返します。
列名を修飾することにより、次のクエリに示すようなエラー メッセージが表示されます。
SELECT ColA FROM X1 WHERE ColA in (Select X2.ColB FROM X2)
サーバー: メッセージ 207、レベル 16、状態 3、行 1
列名 'ColB' が無効です。
人々は何年もの間、この問題について不平を言ってきましたが、マイクロソフトはそれを修正するつもりはありません. 結局のところ、それは基本的に次のように述べている標準に準拠しています。
現在のスコープで列 x が見つからない場合は、参照が見つかるまで、次の外側のスコープにトラバースします。
次の接続の「バグ」の詳細と、この動作が設計によるものであり、変更されないという複数の公式の確認 (したがって、自分の動作を変更する必要があります。つまり、常にエイリアスを使用します)。
Connect #338468 : サブクエリでの CTE 列名の解決が検証されていない
Connect #735178 : IN 演算子を使用すると、T-SQL サブクエリが機能しない場合がある
Connect #302281 : 存在しない列によりサブクエリが無視される
Connect #772612 : エイリアス エラーIN 演算子
Connect 内では報告されない #265772 : sub select を使用するバグ
あなたの場合、ID、OID、および PID よりも意味のある名前を使用すると、この「エラー」が発生する可能性がはるかに低くなります。Order.PID
またはを指していますPerson.id
か?Person.PID
人々があなたに尋ねなくてもリレーションシップを把握できるように、テーブルを設計します。Aは、スキーマ内のどこにあるかに関係なく、PersonID
常にa である必要があります。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?
);