Question

I have tried so many combinations so maybe I'm just simply doing it wrong. Well, I definitely am doing it wrong.

I know that code is always requested on Stack Overflow but it'll confuse the question as my code has now mutated into another language.

Confusion:

There's two WHERE clauses and no matter where I place it, I either get an error or the JOIN doesn't work

Problem:

I have 4 tables:

customers - I need ALL the rows returned even if there's no payment to it but only if customer_status = 1

payments - contains customer_id linked to customers table - I need the SUM returned from payment_amount only if payment_status = 1

branches - contains customer_id linked to customers table

managers - contains branch_id linked to branches table

CUSTOMER    |    TOTAL_RECEIVED    |    BRANCH      |    MANAGER_NAME
----------------------------------------------------------------------
Pepsi       |    £1000             |    London      |    Mr Smith
Coca Cola   |                      |    Manchester  |    Mr Beckham
Dr Pepper   |    £2500             |    Shanghai    |    Mr Miagi
Duff        |                      |    Springfield |    Mr Simpson

As you can see, coca cola and duff haven't paid (no record in payment table) but it should still list

  • So customers should all show up if customer_status = 1
  • SUM of payment only if it's in database and payment_status = 1
  • Branch and Manager should list for that customer as it's always in database
  • Managers is in its own table as there's many and assigned to different branches at different times (as I have a feeling someone might ask)

Fields selected and where summary

c.customer_id, c.customer_companyname, c.customer_status FROM customers c WHERE c.customer_status = 1

SUM(p.payment_amount) as total_received, p.customer_id, p.payment_status FROM payments p WHERE p.payment_status = 1

b.branch_id, b.branch, b.customer_id FROM branches b WHERE b.customer_id = c.customer_id

m.manager_id, m.manager_name, m.branch_id FROM managers m WHERE m.branch_id = b.branch_id
Was it helpful?

Solution

The key to solving this problem is putting the condition in payment into the join condition:

SELECT 
    c.customer_id,
    c.customer_companyname,
    c.customer_status,
    SUM(p.payment_amount) as total_received,
    b.branch_id,
    b.branch,
    m.manager_id,
    m.manager_name
FROM customers c
LEFT JOIN payments p on p.customer_id = c.customer_id
  AND p.payment_status = 1 -- Payment condition here!
LEFT JOIN branches b ON b.customer_id = c.customer_id
LEFT JOIN managers m ON m.branch_id = b.branch_id
WHERE c.customer_status = 1
GROUP BY
    c.customer_id,
    c.customer_companyname,
    c.customer_status,
    b.branch_id,
    b.branch,
    m.manager_id,
    m.manager_name

Two main points:

  • The reason you can't have the payments condition in the WHERE clause is that missed joins have nulls in the joined column, so the test on payment status won't be true and you'll filter out customers with no payments with status 1, instead if returning 0 for the sum. By putting the condition into the join condition, it only matches suitable rows, but will still allow the customer row to be returned without any.
  • It's OK to have non-key related conditions on a join condition. Most people don't realise this. It's good to keep in mind.

Note that your join conditions look incorrect. I would expect that branch should match on c.branch_id = b.brach_id and similarly for manager, but I'll leave that to you to sort out.

OTHER TIPS

select c.customer_id,c.customer_companyname,c.customer_status,SUM(p.payment_amount) as total_received from customers c
 left join payments p on (p.customer_id=c.customer id and p.payment_status=1)
 left join branches b on (b.customer_id=c.customer_id) 
 left join managers m on (m.branch_id=b.branch_id) 
 where customer_status=1 group by p.customer_id order by p.customer_id

It's a complex query and I don't have your database to compare against, but I think the solution for you is to left join all your tables to customers and then group by the table you are summing.

Here's an example of aggregating across tables, in case there's a hole in my code: http://www.artfulsoftware.com/infotree/qrytip.php?id=105

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top