Home > OS >  Return value only if all the rows in a query match criteria in two specific fields
Return value only if all the rows in a query match criteria in two specific fields

Time:12-22

Consider the following tables in SQL Server:

Table Orders:

OrderID OrderNumber
1 1234

Table OrderItems:

OrderItemID OrderID Received Scheduled
1 1 N N
2 1 X B
3 1 X X
4 1 X X
5 1 N B

In table OrderItems, Received and Scheduled can only have values 'N', 'X', or 'B'. I can't seem to figure out how to do the following:

select OrderNumber where Received != 'B' --if any of the Received values are 'B', then nothing should come back and Received = 'X' and Scheduled = 'B'.

Given the above table, OrderNumber should come back once in the result set. However, if 'B' appears in the Received column even once, then nothing should come back, because that fails the conditions.

So basically, I would like to get the OrderNumber back only if Received is either all 'X' or 'N' and 1 or more rows has Received = 'X' and Scheduled = 'B'.

I've tried using an all type clause with various conditions to do this, along with some other query ideas, but it doesn't take into account all rows in the final result:

select o.OrderNumber from Orders o 
inner join OrderItems oi on oi.OrderID = o.OrderID 
where o.OrderNumber = '1234' 
and oi.Received = all
    (select oi.Received from Orders o 
inner join OrderItems oi on oi.OrderID = o.OrderID 
where o.OrderNumber = '1234' 
and oi.Received in ('X', 'N') and oi.Received != 'B')

The above will give back all rows (so 5 OrderNumber results), even if I change row 4 to Received = 'B', for instance. The expected result for this should be:

OrderNumber
1 1234

Because the OrderItems table above has one row that matches the criteria requested (Received = 'X' and Scheduled = 'B') with no rows where Received = 'B'. If I changed row 4 to Received = 'B', then no results should come back.

SQL is not my strong suit, so any help here is much appreciated. I feel like a having clause or maybe a temp table would help, but this query will run over a large number of orders, and I worry about performance.

Thank you for your help!

Edited to make the query area look cleaner, fix the query, and explain the result

CodePudding user response:

You can use EXISTS and NOT EXISTS statements for this.

SELECT o.OrderNumber
FROM Orders o
WHERE o.OrderNumber = '1234'
      AND EXISTS
(
    SELECT *
    FROM OrderItems
    WHERE OrderNumber = o.OrderNumber
        AND Received = 'X'
        AND Scheduled = 'B'
)
      AND NOT EXISTS
(
    SELECT *
    FROM OrderItems
    WHERE OrderNumber = o.OrderNumber
          AND Received = 'B'
)

CodePudding user response:

If I understand correctly you can efficiently use a combination of exists and an aggregate given your 3 alphanumeric values:

select OrderNumber
from Orders o
where exists (
    select *
    from orderitems oi
    where oi.OrderId = o.OrderId
    group by orderid 
    having Min(received) > 'B'
);
  • Related