Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SQL IN-Abfrage erzeugt seltsames Ergebnis

Dieses Verhalten ist zwar nicht intuitiv, aber in der Microsoft Knowledge Base sehr gut definiert:

KB #298674 :PRB:Unterabfrage löst Spaltennamen in äußere Tabellen auf

Aus diesem Artikel:

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)

Die Leute beschweren sich seit Jahren über dieses Problem, aber Microsoft wird es nicht beheben. Immerhin entspricht es dem Standard, der im Wesentlichen besagt:

Weitere Informationen finden Sie in den folgenden Connect "Bugs" zusammen mit mehreren offiziellen Bestätigungen, dass dieses Verhalten beabsichtigt ist und sich nicht ändern wird (also müssen Sie Ihres ändern - d.h. immer Aliase verwenden ):

Connect #338468 :CTE Column Name Resolution in Sub Query is not valided
Connect #735178 :T-SQL-Unterabfrage funktioniert in einigen Fällen nicht, wenn der IN-Operator verwendet wird
Connect #302281 :Nicht vorhandene Spalte führt dazu, dass Unterabfrage ignoriert wird
Connect #772612 :Alias-Fehler wird nicht gemeldet, wenn er sich innerhalb eines IN-Operators befindet
Connect #265772 :Bug using sub auswählen

In Ihrem Fall wird dieser "Fehler" wahrscheinlich viel seltener auftreten, wenn Sie aussagekräftigere Namen als ID, OID und PID verwenden. Führt Order.PID aus zeigen Sie auf Person.id oder Person.PID ? Entwerfen Sie Ihre Tabellen so, dass die Leute die Beziehungen herausfinden können, ohne Sie fragen zu müssen. Eine PersonID sollte immer eine PersonID sein , egal wo im Schema es sich befindet; dasselbe mit einer OrderID . Das Einsparen von ein paar Zeichen beim Tippen ist kein guter Preis für ein völlig mehrdeutiges Schema.

Sie könnten ein EXISTS schreiben Klausel stattdessen:

... 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?
);