Vérifiez si l'une des valeurs se trouve dans un résultat de sous-requête


8

J'ai une sous-requête compliquée qui renvoie une liste d'ID de commande. J'ai besoin d'obtenir une liste de clients qui ont ces commandes. Le problème est qu'il existe deux façons d'affecter un client à une commande (l'un des deux champs). Je pourrais juste faire des trucs comme ça:

 select *
 from Customers
 where orderId in (select...) 
 or secondaryOrderId in (select ...)

Le problème est que la sous-requête est énorme, à la fois en temps d'exécution et en espace d'écran. Existe-t-il un moyen de vérifier si l' un des champs contient l'un des résultats souhaités?

Réponses:


10

Essayer:

where exists (select * .... 
        where Customers.orderId = ... 
        or Customers.secondaryId = ...
     )

Par exemple, si vous envisagiez:

where orderId in (select value from ...)
or secondaryorderid in (select value from ...)

Ensuite, vous faites en sorte que vous n'appeliez votre sous-requête qu'une seule fois, et que vous y intégriez votre clause OR.

 where exists (select * from ... 
        where Customers.orderId = value 
        or Customers.secondaryOrderId = value
     )

Le but de tout cela est de s'assurer que la sous-requête compliquée n'est exécutée qu'une seule fois. Cela ne se produit pas avec un CTE ou en remplaçant deux IN par deux EXISTS.


3

Votre requête devrait probablement être réécrite comme un existsau lieu d'unin

Voir ce lien pour plus d'exemples.

Votre requête ressemblerait alors à quelque chose comme

select *
from Customers C
where exists (select 'x' from ordertable o where c.orderid = o.orderid) 
or exists (select 'x' from ordertable o where c.secondaryOrderId = o.orderid) 

Si les deux sous-requêtes sont identiques, vous pouvez supprimer l'une d'entre elles et les combiner comme ceci

select *
from Customers C
where exists (select 'x' from ordertable o where c.orderid = o.orderid or c.secondaryOrderId = o.orderid) 

2

Pourquoi ne pas utiliser une withclause aka Common Table Expression ? Il est conçu à cet effet (entre autres).

with orderIds as (
  select orderId
  from ...
)
select *
from Customers
where orderId in (select orderId from orderIds) 
or secondaryOrderId in (select orderId from orderIds);

Voir https://msdn.microsoft.com/en-us/library/ms175972%28v=sql.105%29.aspx pour la documentation de Microsoft.


3
Pas vraiment beaucoup d'avantages en faisant cela en termes de temps pris. Le CTE n'est pas mis en cache et sera exécuté les deux fois qu'il sera référencé. stackoverflow.com/questions/22041244/…
Mark Sinkinson

1
D'ACCORD. Il semble que chaque SGBD traite CTE différemment.
Colin 't Hart

Un CTE n'est pas conçu à cet effet. Il serait toujours développé deux fois dans la requête principale. Essayez de voir ...
Rob Farley

1
Et la documentation de Microsoft est trompeuse "[Un CTE] peut être considéré comme un jeu de résultats temporaire" que j'ai interprété comme signifiant que les résultats sont mis en cache ou autrement stockés comme une table temporaire. Il existe maintenant une autre solution T-SQL qui n'a pas encore été mentionnée.
Colin 't Hart

@ Colin'tHart Bienvenue dans le monde de la documentation Microsoft :-)
Mark Sinkinson
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.