'SQL - Find customers who bought all products
Suppose I have 2 tables:
Table A
C_ID P_ID
1 1
1 2
2 1
Table B
P_ID
1
2
In Table A, C_ID
and P_ID
serve as PK, in Table B P_ID
is the PK
I want to find all C_ID that bought all products in B (basically all P_ID in B). In the example above that would C_ID = 1
Can you check if below is correct? Any alternatives that are more efficient/easier?
SELECT A.C_ID
FROM A
JOIN B ON A.P_iD = B.P_ID
GROUP BY A.C_ID
HAVING COUNT(DISTINCT A.P_ID) >= (SELECT COUNT(DISTINCT P_ID) FROM B)
Thanks!
Solution 1:[1]
following query works with MySQL and SQL Server.
you can do this without JOIN
select
c_id
from tableA
group by
c_id
having count(distinct p_id) = (select count(*) from tableB)
Solution 2:[2]
The other answer is not correct, as it only verifies that a customer bought as many distinct items as there are items in the product table. If however you table looked like this:
C_ID P_ID
1 1
1 3
2 1
the query would return customer 1 even though Customer 1 did not but all the products (namely, they did not buy product P_ID=2
.
Generalized Solution
what you are looking for is called a division query. The strategy is based on a double negation, think:
"give me all the customers for which there is no product, that has never been purchased"
in SQL:
-- define a customer table
WITH customers as (
SELECT DISTINCT C_ID
FROM A)
-- all customers who have not
SELECT *
FROM customers as outer
WHERE NOT EXISTS
( -- all products which have not
SELECT *
FROM B as inner
WHERE NOT EXISTS
( -- ever been purchased
SELECT*
FROM A as matchtable
WHERE matchtable.C_ID=outer.C_ID
AND matchtable.P_ID=inner.P_ID)
)
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | safex |