Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intersect Select Statements on Specific Columns

Tags:

sql

sql-server

I've a table of SalesDetails, looking like this:

InvoiceID, LineID, Product

1,1,Apple
1,2,Banana
2,1,Apple
2,2,Mango
3,1,Apple
3,2,Banana
3,3,Mango

My requirement is to return rows where an Invoice contained sales of both: Apple AND Banana, but if there are other products on such an invoice, I don't want those.

So the result should be:

1,1,Apple
1,2,Banana
3,1,Apple
3,2,Banana

I tried the following:

Select * from SalesDetails where Product = 'Apple'
Intersect
Select * from SalesDetails where Product = 'Banana'

Didn't work, because it seems Intersect needs to match all the columns.

What I'm hoping to do is:

Select * from SalesDetails where Product = 'Apple'
Intersect ----On InvoiceID-----
Select * from SalesDetails where Product = 'Banana'

Is there a way to do this?

Or do I have to first Intersect on InvoiceIDs only using my criteria, then select the rows of those InvoiceIDs where the criteria is matched again, I.e.:

Select * From SalesDetails
Where Product In ('Apple', 'Banana') And InvoiceID In 
  (
  Select InvoiceID from SalesDetails where Product = 'Apple'
  Intersect
  Select InvoiceID from SalesDetails where Product = 'Banana'
  )

Which seems somewhat wasteful as it's examining the criteria twice.

like image 622
Xinneh Avatar asked Apr 27 '15 07:04

Xinneh


People also ask

How do I INTERSECT two columns in SQL?

The INTERSECT clause in SQL is used to combine two SELECT statements but the dataset returned by the INTERSECT statement will be the intersection of the data-sets of the two SELECT statements. In simple words, the INTERSECT statement will return only those rows which will be common to both of the SELECT statements.

How do you find the intersection of two queries in SQL?

The SQL INTERSECT clause/operator is used to combine two SELECT statements, but returns rows only from the first SELECT statement that are identical to a row in the second SELECT statement. This means INTERSECT returns only common rows returned by the two SELECT statements.

How does SQL INTERSECT work?

SQL INTERSECT operator combines two select statements and returns only the dataset that is common in both the statements. To put it simply, it acts as a mathematical intersection. In mathematics, the intersection of A and B is the common data present in both A and B.


4 Answers

Okay this time I've managed to get reuse of the Apple/Banana info by using a CTE.

with sd as (
Select * from SalesDetails 
where (Product in ('Apple', 'Banana'))
)
Select * from sd where invoiceid in (Select invoiceid from 
  sd group by invoiceid having Count(distinct product) = 2)

SQL Fiddle

like image 54
Leon Bambrick Avatar answered Oct 16 '22 07:10

Leon Bambrick


Do it with conditional aggregation:

select * 
from SalesDetails
where product in ('apple', 'banana') and invoiceid in(
select invoiceid
from SalesDetails
group by invoiceid
having sum(case when product in('apple', 'banana') then 1 else 0 end) >= 2)
like image 22
Giorgi Nakeuri Avatar answered Oct 16 '22 08:10

Giorgi Nakeuri


I think OP's suggestion is about the best one can do. The following might be faster, although I expect the difference to be slight and I have not done any benchmarking.

Select * From SalesDetails
Where Product ='Apple' And InvoiceID In
(
Select InvoiceID from SalesDetails where Product = 'Banana'
)
union all
select * from SalesDetails
Where Product ='Banana' And InvoiceID In
(
Select InvoiceID from SalesDetails where Product = 'Apple'
)
like image 3
Taemyr Avatar answered Oct 16 '22 08:10

Taemyr


A self-join will solve the problem.

SELECT T1.*
FROM SalesDetails T1 
INNER JOIN SalesDetails T2 ON T1.InvoiceId = T2.InvoiceId
   AND (T1.Product = 'Apple' AND T2.Product = 'Banana'
     OR T1.Product = 'Banana' AND t2.Product = 'Apple')
like image 3
qxg Avatar answered Oct 16 '22 09:10

qxg