'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