Reputation: 1726
Let's say I have 2 tables:
tOrder tOrderLine
------ ----------
OrderID OrderID
Other Fields ProductID
Other Fields
I want to get back all orders that have a certain 2 products on the same order. Currently, I'm doing:
select o.OrderID
from tOrder o
inner join tOrderLine ol on o.OrderID = ol.OrderID
inner join tOrderLine ol2 on o.OrderID = ol2.OrderID
where ol.ProductID = 67
and ol2.ProductID = 68
This works and gives me the results I need, but it seems a little hokey. Also, if I wanted to get all orders that have a set of 10 items, the query is going to get monstrous.
Is there a better way to do what I'm looking for?
Upvotes: 1
Views: 4933
Reputation: 27427
Try this
Select Distinct a.*
From tOrder a
inner join tOrderLine b on a.orderId = b.orderId
Where a.orderId in
(
Select orderId
From tOrderLine
Where
productId in (68,69)
--replace with set of products you want
Group by orderId
Having Count(Distinct productId) = 2
---replace with 10 if you want to return orders with 10 items
)
Upvotes: 2
Reputation: 10038
There are 2 simple ways I can think to do it:
tOrderLine
twice. Exactly how you did it. I actually would have never thought of that. It was an interesting solution when I saw it.EXISTS
clauses. For each tOrder row, check if there exists a row in tOrderLine
corresponding to it and one of the products.For example:
select tOrder.OrderID
from tOrder o
where exists (select 1 from tOrderLine ol where ol.OrderID = o.OrderID and ol.ProductID = 67)
and exists (select 1 from tOrderLine ol where ol.OrderID = o.OrderID and ol.ProductID = 68)
This is how I would write it, simply because it's more obvious what the query is doing. On the other hand, yours seems easier for the parser to optimize.
I'd be curious to know if you look at the execution plan of either one if they are the same. The correlated sub-queries could be rewritten internally to be inner joins.
Upvotes: 3
Reputation: 156978
You could try to solve it using a distinct count on a having
:
select t.OrderId
, count(*)
from tOrder t
join tOrderLine o
on t.OrderID = o.OrderID
where o.ProductId in (67, 68)
group
by t.OrderId
having count(distinct o.ProductId) = 2
Upvotes: 2