Получение идентификаторов, которые имеют одно конкретное значение, но не имеют другого конкретного значения

#tsql

#tsql

Вопрос:

У меня есть два столбца

 OrderId  OrderStatus
120      1
120      2
121      1
123      1
123      2
  

Я хочу получить только строку с OrderID 121, потому что у нее был OrderStatus 1, но у нее нет OrderStatus 2.

Ответ №1:

Поскольку вы не упоминаете, что существует « StatusDate или что-то в этом роде, я собираюсь принять

Я хочу вернуть строку только с OrderID 121, потому что у нее был OrderStatus 1, НО У НЕЕ НИКОГДА НЕ БЫЛО OrderStatus 2.

чтобы означать

Я хочу вернуть только OrderID 121, потому что есть строка с OrderID 121 и OrderStatus 1, но нет строки с OrderID 121 и OrderStatus 2

С SQL 2005 и более поздними EXCEPT версиями это делает это чрезвычайно кратким:

 SELECT OrderId FROM [Order] WHERE OrderStatus = 1
EXCEPT
SELECT OrderId FROM [Order] WHERE OrderStatus = 2
  

EXCEPT возвращает различные значения, поэтому в дальнейшем нет необходимости DISTINCT .

Ответ №2:

Вы можете использовать самосоединение, выполнив поиск OrderStatus = 1 слева и пропущенное соединение с OrderStatus = 2 справа:

 declare @t table(OrderID int, OrderStatus int)
insert into @t values (120, 1)
insert into @t values (120, 2)
insert into @t values (121, 1)
insert into @t values (123, 1)
insert into @t values (123, 2)

select t1.* 
from @t 
    t1 left join 
    (select * from @t where OrderStatus = 2) as t2 on t2.OrderID = t1.OrderID 
where 
    t1.OrderStatus = 1 and
    t2.OrderID is null
  

Ответ №3:

Если статусы ваших заказов равны только 1 и 2, и заказы должны иметь статус 1 в какой-то момент, прежде чем стать статусом 2, вы можете выполнить поиск заказов с максимальным значением статуса заказа 1:

   select distinct orderid from orders
group by orderid
  having max(orderstatus) = 1;
  

Демонстрация: http://www.sqlize.com/2k3C2SqMH2

Или, если это не совсем так просто, мы можем более четко указать, что когда-либо не разрешать orderstatus 2, используя not exists предложение:

 select distinct orderid
  from orders o
 where not exists (
     select * from orders o2
     where o2.orderid = o.orderid
       and o2.orderstatus = 2
   );
  

Демонстрация: http://www.sqlize.com/o6fSvWmvaj