Reputation: 12685
I have a many to many relationship, Orders
, OrderProducts
, and Products
. I need a query that gives me a list of products that are NOT in ALL orders, but has been ordered.
______________________
| ORDERS |
_______________________
| OrderID | OrderDate |
| 1 | 1/2/2012 |
| 2 | 1/3/2012 |
| 3 | 1/4/2012 |
| 4 | 1/5/2012 |
| 5 | 1/6/2012 |
______________________
| ORDERPRODUCTS |
_______________________
| OrderID | PRODUCTID |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 2 | 4 |
| 3 | 1 |
| 3 | 5 |
| 4 | 1 |
| 5 | 1 |
__________________________
| PRODUCTS |
__________________________
| PRODUCTID | PRODUCTNAME |
| 1 | Widget 1 |
| 2 | Widget 2 |
| 3 | Widget 3 |
| 4 | Widget 4 |
| 5 | Widget 5 |
| 6 | Widget 6 |
In the provided example, notice that product 1 is in all orders and product 6 is not ordered at all.
I need a query that returns Products 2, 3, 4, and 5.
Also keep in mind that while there aren't many products, there are a few hundred thousand orders in the live database.
Upvotes: 3
Views: 707
Reputation: 6783
SELECT
DISTINCT
PossibleOrderProducts.PRODUCTID
FROM
(
SELECT
Orders.ORDERID,
Products.PRODUCTID
FROM
ORDERS Orders
CROSS JOIN
(
SELECT DISTINCT PRODUCTID FROM ORDERPRODUCTS
) Products
) PossibleOrderProducts
LEFT JOIN ORDERPRODUCTS ActualOrderProducts ON
ActualOrderProducts.ORDERID = PossibleOrderProducts.ORDERID
AND ActualOrderProducts.PRODUCTID = PossibleOrderProducts.PRODUCTID
WHERE
ActualOrderProducts.ORDERID IS NULL
Upvotes: 0
Reputation: 280431
It's Saturday night, so this is probably not the most elegant, but here's one try:
DECLARE @OrderProducts TABLE(OrderID INT, ProductID INT);
DECLARE @Products TABLE(ProductID INT, ProductName VARCHAR(32));
INSERT @Products VALUES
(1,'Widget 1'),(2,'Widget 2'),
(3,'Widget 3'),(4,'Widget 4'),
(5,'Widget 5'),(6,'Widget 6');
INSERT @OrderProducts VALUES
(1,1),(1,2),(2,1),(2,2),(2,3),
(2,4),(3,1),(3,5),(4,1),(5,1);
SELECT p.ProductID, p.ProductName
FROM @Products AS p
WHERE EXISTS -- had been ordered at least once
(
SELECT 1 FROM @OrderProducts
WHERE ProductID = p.ProductID
)
AND EXISTS -- at least one order does NOT include it
(
SELECT 1 FROM @OrderProducts AS o
WHERE NOT EXISTS
(
SELECT 1 FROM @OrderProducts AS o2
WHERE o2.OrderID = o.OrderID
AND o2.ProductID = p.ProductID
)
);
Upvotes: 3
Reputation: 453618
SELECT PRODUCTID
FROM ORDERPRODUCTS
GROUP BY PRODUCTID
HAVING COUNT(DISTINCT OrderID) < (SELECT COUNT(*) FROM ORDERS )
Upvotes: 4