maobe
maobe

Reputation: 77

SQL Query With Count And Joining Table

I have the following three tables:

Customer
id (PK)
name

Product
id(PK)
name
price

Transaction
id(PK)
customer_id(FK ref Customer.id)
product_id(FK ref Product.id)
date_created

I'm running the following query which gives me the the amount of products used per customer:

SELECT p.id, p.name, Count(p.id), p.price
FROM transaction t, product p, customer c
WHERE p.id = t.product_id
      AND  c.id = t.customer_id
      AND c.id = 1
group by p.price, p.name, p.id
ORDER BY p.name ASC;

This works, except that it gives me ONLY the products which the customer has used with their respective count. What I want is the list of ALL the products with a count of 0 for those products which the customer hasn't used. I'm having trouble trying to figure this out since I'm using the Transaction table as a joining table between the customers and the products, and the way I'm finding the count of each product per customer is by a count of records (as you can see in the SQL code above).

I could do:

SELECT *
FROM product
WHERE product.name NOT IN (SELECT p.name
                           FROM transaction t, product p, customer c
                           WHERE p.id = t.product_id
                                 AND  c.id = t.customer_id
                                 AND c.id = 1);

and then somehow programmatically assign 0 to the count in my resultset, but then I'll end up with two lists, one that contains the name of the product, the count of each product, and the price per product that the customer has used, and another list that will contain all the product names, a count of 0, and the price for each product that the customer has not used.

This could be a solution, but it seems far from practical since id be dealing with two list and having to programmatically assign values instead of dealing with one list that would contain all the data that I need, which would affect ordering, etc.

I'm wondering if this is possible or if there's another way to look at this problem.

I hope this is clear enough. I'd appreciate any insight into this!

Mauricio B.

Upvotes: 1

Views: 1021

Answers (3)

Eric
Eric

Reputation: 267

You have to do two select queries and join them:

select prodcust.custname, prodcust.prodname, prodcust.prodId, 
    isnull(tranCount,0) as count, prodcust.price 
from
(
    select p.name as prodname, p.id as prodID, c.name as custname, c.id as 
        custid, p.price 
    from product p, customer c
)
as prodcust

left join 

(
    select p.price, p.id, c.id as custid, count(t.id) as tranCount
    from Transaction t
    inner join customer c
       on c.id = t.customer_id
    inner join product p
       on t.product_id = p.id
    group by p.price, p.id, c.id
) as trans 
on prodcust.custid = trans.custid
   and prodcust.prodID = trans.id
order by custname, prodname

Upvotes: 0

sticky bit
sticky bit

Reputation: 37472

This should work in most DBMS. It groups the transaction table for all the customers products and gets their count. This is then left joined to the products. As it is a left join, all products will be included. For those products the customer hasn't used the joined columns will be NULL. So will be the count. With the coalesce() function returning the first argument not null, we get 0 as count for those and the actual count for the others. If your actual DBMS doesn't support coalesce() you might have to replace that with the respective DBMS specific function.

SELECT p.id,
       p.name,
       coalesce(t.count, 0) count,
       p.price
       FROM product p
            LEFT JOIN (SELECT t.product_id,
                              count(*) count
                              FROM transaction t
                              WHERE t.customer_id = 1
                              GROUP BY t.product_id) t
                      ON t.product_id = p.id
       ORDER BY p.name ASC;

Upvotes: 1

Gordon Linoff
Gordon Linoff

Reputation: 1269773

Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.

Your problem is specifically that you need a left join:

select p.id, p.name, Count(t.id), p.price
from product p left join
     transaction t
     on p.id = t.product_id and
        t.customer_id = 1
group by p.price, p.name, p.id
order by p.name asc;

Note: you do not need the customer table. The id is in the transaction table.

Upvotes: 1

Related Questions