Controlla se uno dei valori è in un risultato di subquery


8

Ho una sottoquery complicata che restituisce un elenco di ID ordine. Devo ottenere un elenco di clienti che hanno questi ordini. Il problema è che esistono due modi per assegnare un cliente a un ordine (uno dei due campi). Potrei semplicemente fare cose come questa:

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

Il problema è che la subquery è enorme, sia nel tempo necessario per l'esecuzione, sia nello spazio dello schermo che richiede. C'è un modo per verificare se uno dei campi contiene uno dei risultati desiderati?

Risposte:


10

Provare:

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

Ad esempio, se avevi intenzione di:

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

Quindi lo fai in modo da chiamare la tua subquery una sola volta e incorporare la tua clausola OR.

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

Lo scopo di tutto ciò è garantire che la complessa subquery venga eseguita una sola volta. Ciò non accade con un CTE o sostituendo due IN con due EXISTS.


3

La tua query dovrebbe probabilmente essere riscritta come existsinvece che comein

Vedi questo link per altri esempi.

La tua query avrebbe quindi un aspetto simile a

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) 

Se entrambe le subquery sono uguali, puoi rimuoverne una e combinarle in questo modo

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

2

Perché non utilizzare una withclausola Common Table Expression aka ? È progettato proprio per questo scopo (tra gli altri).

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

Vedere https://msdn.microsoft.com/en-us/library/ms175972%28v=sql.105%29.aspx per la documentazione di Microsoft.


3
Non ne traggo molto beneficio in termini di tempo impiegato. Il CTE non viene memorizzato nella cache e verrà eseguito entrambe le volte in cui viene fatto riferimento. stackoverflow.com/questions/22041244/...
Mark Sinkinson

1
OK. Sembra che ogni DBMS gestisca CTE in modo diverso.
Colin 't Hart,

Un CTE non è progettato per questo scopo. Sarebbe comunque espanso nella query principale due volte. Prova a vedere ...
Rob Farley,

1
E la documentazione di Microsoft è fuorviante "[A CTE] può essere pensato come un set di risultati temporaneo", che ho interpretato nel senso che i risultati vengono memorizzati nella cache o altrimenti archiviati come una tabella temporanea. Ora c'è un'altra soluzione T-SQL che non è stata ancora menzionata.
Colin 't Hart,

@ Colin'tHart Benvenuti nel mondo della documentazione Microsoft :-)
Mark Sinkinson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.