I have a classical 1:n relation between two tables as given below:
I need to select only those customers where 'NOT OrderDate IS NULL' for all their orders. I started with
SELECT Customers.Id, Customers.LastName
FROM Customers, Orders
WHERE Customers.Id = Orders.CustomerId AND NOT Orders.OrderDate IS NULL AND ...
and wanted to build further with 'FOR ALL' but failed.
I tried the suggestions given in the answers but none gave the correct results.
Here is my workaround with two temp tables as shown below:
DECLARE @TableA TABLE (
Id int,
CountA int
)
DECLARE @TableB TABLE (
Id int,
CountB int
)
INSERT INTO @TableA (Id, CountA)
SELECT Customers.Id, COUNT(Orders.Id)
FROM Customers INNER JOIN
Orders ON Customers.Id = Orders.CustomerId
GROUP BY Customers.ID
INSERT INTO @TableB (Id, CountB)
SELECT Customers.Id, COUNT(Orders.Id)
FROM Customers INNER JOIN
Orders ON Customers.Id = Orders.CustomerId
WHERE (NOT Orders.OrderDate IS NULL)
GROUP BY Customers.ID
Select tA.Id
FROM @TableA tA INNER JOIN @TableB tB on tA.Id = tB.Id
WHERE tA.CountA = tB.CountB
Both temp tables differ only in that respect that the first selects the group count without a condition in Orders and the second temp selects them with a condition. Then joining the two temp tables where CountA = CountB gives only those customers where all related Orders fulfill the condition.
If someone finds a more elegant way, please let me know.
Any suggestions how to tackle this?
In cases like this, you need to think not of finding the records where all the related records meet a condition.
Instead, think of finding all the records WHERE there does NOT EXIST a related record that breaks the condition.
The most straightforward way to write this query, is with ALL :
SELECT Customers.Id, Customers.LastName
FROM Customers
WHERE '2000-01-01' < ALL(SELECT OrderDate FROM Orders WHERE Orders.CustomerId = Customers.Id)
You could also write it as a group query on the orders table, something like
WITH CustomerOrderDateRange(CustomerId, MinOrderDate, MaxOrderDate) AS (
SELECT CustomerId, MIN(OrderDate), MAX(OrderDate)
FROM Orders
GROUP BY CustomerId
)
SELECT Customers.Id, Customers.LastName
FROM Customers
JOIN CustomerOrderDateRange
ON Customers.Id = CustomerOrderDateRange.CustomerId
WHERE
CustomerOrderDateRange.MinOrderDate > '2000-01-01'
I think this is cleaner if you need multiple criteria, for example a max date range as well.
Just locate the records you want to exclude from it, and put in a not in clause
select *
from Customers
where Customers.Id not in (
SELECT Customers.Id
FROM Customers
join Orders on Customers.Id = Orders.CustomerId
WHERE Orders.OrderDate < '2000-01-01'
group by Customers.Id
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.