Compruebe si alguno de los valores está en un resultado de subconsulta


8

Tengo una subconsulta complicada que devuelve una lista de ID de pedidos. Necesito obtener una lista de clientes que tienen estos pedidos. El problema es que hay dos formas de asignar un cliente a un pedido (uno de los dos campos). Podría hacer cosas como esta:

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

El problema es que la subconsulta es enorme, tanto en tiempo de ejecución como en espacio de pantalla. ¿Hay alguna manera de verificar si uno de los campos contiene uno de los resultados deseados?

Respuestas:


10

Tratar:

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

Por ejemplo, si planeabas:

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

Luego lo hace de modo que solo llame a su subconsulta una vez, y construya su cláusula OR en ella.

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

El objetivo de esto es garantizar que la subconsulta complicada solo se ejecute una vez. Eso no sucede con un CTE, o al reemplazar dos IN por dos EXISTS.


3

Su consulta probablemente debería reescribirse como un en existslugar de unin

Vea este enlace para más ejemplos.

Su consulta luego se vería algo similar 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) 

Si ambas subconsultas son iguales, puede eliminar una de ellas y combinarlas así

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

2

¿Por qué no usar una withcláusula de expresión de tabla común aka ? Está diseñado exactamente para este propósito (entre otros).

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

Consulte https://msdn.microsoft.com/en-us/library/ms175972%28v=sql.105%29.aspx para obtener la documentación de Microsoft.


3
Realmente no hay mucho beneficio al hacer esto en términos de tiempo empleado. El CTE no se almacena en caché y se ejecutará las dos veces que se hace referencia. stackoverflow.com/questions/22041244/…
Mark Sinkinson

1
OKAY. Parece que cada DBMS maneja CTE de manera diferente.
Colin 't Hart

Un CTE no está diseñado para este propósito. Todavía se expandiría a la consulta principal dos veces. Intenta ver ...
Rob Farley

1
Y la documentación de Microsoft es engañosa "[A CTE] puede considerarse como un conjunto de resultados temporal", que interpreté en el sentido de que los resultados se almacenan en caché o se almacenan como una tabla temporal. Ahora hay otra solución T-SQL que aún no se ha mencionado.
Colin 't Hart

@ Colin'tHart Bienvenido al mundo de la documentación de Microsoft :-)
Mark Sinkinson
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.