Проверьте, есть ли какое-либо из значений в результате подзапроса


8

У меня сложный подзапрос, который возвращает список идентификаторов заказа. Мне нужно получить список клиентов, у которых есть эти заказы. Проблема заключается в том, что существует два способа назначения клиента для заказа (одно из двух полей). Я мог бы просто сделать что-то вроде этого:

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

Проблема в том, что подзапрос огромен, как во времени, необходимом для выполнения, так и в пространстве экрана, которое он занимает. Есть ли способ проверить, содержит ли одно из полей один из желаемых результатов?

Ответы:


10

Пытаться:

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

Например, если вы планировали:

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

Затем вы делаете так, что вы вызываете свой подзапрос только один раз и встраиваете в него предложение OR.

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

Весь смысл этого состоит в том, чтобы гарантировать, что сложный подзапрос выполняется только один раз. Этого не происходит с CTE или заменой двух IN на два EXISTS.


3

Ваш запрос, вероятно, должен быть переписан как existsвместоin

Смотрите эту ссылку для большего количества примеров.

Ваш запрос будет выглядеть примерно так:

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) 

Если оба подзапроса одинаковы, вы можете удалить один из них и объединить их так

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

2

Почему бы не использовать выражение Common Table Expression aka with? Он предназначен именно для этой цели (среди прочих).

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

См. Https://msdn.microsoft.com/en-us/library/ms175972%28v=sql.105%29.aspx для документации Microsoft.


3
Не очень много пользы от этого с точки зрения затраченного времени. CTE не кэшируется и будет выполняться оба раза, когда на него ссылаются. stackoverflow.com/questions/22041244/…
Марк Синкинсон

1
ХОРОШО. Кажется, каждая СУБД обрабатывает CTE по-своему.
Colin 't Hart

CTE не предназначен для этой цели. Он все равно будет расширен в основной запрос дважды. Попробуй и посмотри ...
Роб Фарли

1
И документация Microsoft вводит в заблуждение «[CTE] можно рассматривать как временный набор результатов», который я интерпретировал как означающий, что результаты кэшируются или иным образом хранятся как временная таблица. Теперь есть еще одно решение T-SQL, которое еще не упоминалось.
Colin 't Hart

@ Colin'tHart Добро пожаловать в мир документации Microsoft :-)
Марк Синкинсон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.