Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

La requête SQL IN produit un résultat étrange

Ce comportement, bien que peu intuitif, est très bien défini dans la base de connaissances de Microsoft :

KB #298674 :PRB :la sous-requête résout les noms de colonne en tables externes

Extrait de cet article :

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)

Les gens se plaignent de ce problème depuis des années, mais Microsoft ne va pas le résoudre. Il est, après tout, conforme à la norme, qui stipule essentiellement :

Plus d'informations dans les "bogues" Connect suivants ainsi que plusieurs confirmations officielles que ce comportement est voulu et ne changera pas (vous devrez donc changer le vôtre - c'est-à-dire toujours utiliser des alias ):

Connect #338468 :La résolution du nom de colonne CTE dans la sous-requête n'est pas validée
Connect #735178 :la sous-requête T-SQL ne fonctionne pas dans certains cas lorsque l'opérateur IN est utilisé
Connect #302281 :une colonne inexistante entraîne l'ignorance de la sous-requête
Connect #772612 :l'erreur d'alias n'est pas signalée dans un opérateur IN
Connect #265772 :Bug utilisant sub sélectionner

Dans votre cas, cette "erreur" sera probablement beaucoup moins susceptible de se produire si vous utilisez des noms plus significatifs que ID, OID et PID. Est-ce que Order.PID pointe vers Person.id ou Person.PID ? Concevez vos tableaux de manière à ce que les gens puissent comprendre les relations sans avoir à vous le demander. Un PersonID doit toujours être un PersonID , peu importe où il se trouve dans le schéma ; idem avec un OrderID . Enregistrer quelques caractères de frappe n'est pas un bon prix à payer pour un schéma complètement ambigu.

Vous pouvez écrire un EXISTS clause à la place :

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