Verifique se algum dos valores está em um resultado de subconsulta

8

Eu tenho uma subconsulta complicada que retorna uma lista de IDs de pedidos. Preciso obter uma lista de clientes que possuem esses pedidos. O problema é que existem duas maneiras de atribuir um cliente a um pedido (um dos dois campos). Eu poderia fazer coisas assim:

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

O problema é que a subconsulta é enorme, tanto no tempo necessário para executar quanto no espaço de tela necessário. Existe uma maneira de verificar se um dos campos contém um dos resultados desejados?

user63844
fonte

Respostas:

10

Tentar:

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

Por exemplo, se você estava planejando:

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

Então você faz isso para que você chame sua subconsulta apenas uma vez e construa sua cláusula OR nela.

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

O objetivo disso é garantir que a subconsulta complicada seja executada apenas uma vez. Isso não acontece com um CTE ou substituindo dois INs por dois EXISTSs.

Rob Farley
fonte
3

Sua consulta provavelmente deve ser reescrita como um em existsvez de umin

Veja este link para mais exemplos.

Sua consulta pareceria algo ao longo das linhas de

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 as duas subconsultas forem iguais, você poderá remover uma delas e combiná-las da seguinte maneira

select *
from Customers C
where exists (select 'x' from ordertable o where c.orderid = o.orderid or c.secondaryOrderId = o.orderid) 
Tom V - tente topanswers.xyz
fonte
2

Por que não usar uma withcláusula Common Table Expression aka ? Ele foi projetado exatamente para esse fim (entre outros).

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 obter a documentação da Microsoft.

Colin 't Hart
fonte
3
Não é realmente muito útil fazer isso em termos de tempo gasto. O CTE não é armazenado em cache e será executado nas duas vezes em que for referenciado. stackoverflow.com/questions/22041244/…
Mark Sinkinson
11
ESTÁ BEM. Parece que cada DBMS lida com o CTE de maneira diferente.
Colin 't Hart
Um CTE não foi projetado para esse fim. Ainda seria expandido para a consulta principal duas vezes. Experimente e veja ...
Rob Farley
11
E a documentação da Microsoft é enganosa "[Um CTE] pode ser considerado um conjunto de resultados temporário", que interpretei como se os resultados fossem armazenados em cache ou armazenados de outra forma como uma tabela temporária. Agora há outra solução T-SQL que ainda não foi mencionada.
Colin 't Hart
@ Colin'tHart Bem-vindo ao mundo da documentação Microsoft :-)
Mark Sinkinson