Search code examples
mysqlsqljoincountleft-join

COUNT all values in a column with JOIN


I am joining three tables and need to return two separate counts, one showing the total number of unique users who have purchased an item, and the other showing the total number of unique users who haven't purchased an item. These are cropped for brevity, but here are the relevant tables:

user table
+----------+------+------+-----+
| username | colb | colc | etc |
+----------+------+------+-----+
| user1    | *    | *    | *   |
| user2    | *    | *    | *   |
| user3    | *    | *    | *   |
+----------+------+------+-----+
purchase table
+------------+---------+----------+------+
| purchaseID | storeID | username | cost |
+------------+---------+----------+------+
|          1 |       1 | user1    | *    |
|          2 |       1 | user2    | *    |
|          3 |       5 | user2    | *    |
|          4 |       3 | user1    | *    |
+------------+---------+----------+------+
store table
+---------+-----------+-----+
| storeID | storeName | etc |
+---------+-----------+-----+
|       1 | store1    | *   |
|       2 | store2    | *   |
|       3 | store3    | *   |
+---------+-----------+-----+

I am currently using this query to get the unique users who have purchased an item from a store:

SELECT 
    store.storeID storeID, 
    store.storeName storeName, 
    COUNT(DISTINCT CASE WHEN purchase.username IS NOT NULL
                        THEN purchase.purchaseID END) AS purchases
    [Query to retrieve total unique users who have not purchased an item]
FROM store 
LEFT JOIN purchase
    ON store.storeID = purchase.storeID
LEFT JOIN user
    ON purchase.username = user.username
GROUP BY 1, 2

I have tried a few different ways, none of which have worked. The issue I've identified is when the LEFT JOIN happens it only returns the matching results for usernames, thus the COUNT won't include the other users in the user table. I have not had any luck finding a way to fix this, so I'm hoping someone on here can lend me a hand. The results I'm hoping to see should be something like this:

+---------+-----------+-----------+--------------+
| storeID | storeName | purchases | nonPurchases |
+---------+-----------+-----------+--------------+
|       1 | store1    |         2 |            1 |
|       2 | store2    |         0 |            3 |
|       3 | store3    |         1 |            2 |
+---------+-----------+-----------+--------------+

Solution

  • that is actually quite simple.

    First you count all user and subtract te count of distinct purchasers

    SELECT 
        store.storeID storeID, 
        store.storeName storeName, 
        COUNT(DISTINCT CASE WHEN purchase.username IS NOT NULL
                            THEN purchase.purchaseID END) AS purchases,
       (SELECT COUNT(*) FROM User) - COUNT(DISTINCT CASE WHEN purchase.username IS NOT NULL
                            THEN purchase.purchaseID END) AS NON_purchases
    FROM store 
    LEFT JOIN purchase
        ON store.storeID = purchase.storeID
    LEFT JOIN user
        ON purchase.username = user.username
    GROUP BY 1, 2