8

With the following MySQL table containing debit or credit "actions" with associated amounts, how is it possible to select all CLIENT_IDs with a non-zero "balance"? I have tried joining the table to itself in order to calculate all debit and credit totals, but something isn't working correctly.

CLIENT_ID    ACTION_TYPE    ACTION_AMOUNT
1            debit          1000
1            credit         100
1            credit         500
2            debit          1000
2            credit         1200
3            debit          1000
3            credit         1000
4            debit          1000

My MySQL query that doesn't work:

SELECT 
    client_id,
    SUM(t_debits) AS debits, 
    SUM(t_credits) AS credits, 
    SUM(t_debits)-SUM(t_credits) AS balance
FROM table_name AS t_debits
LEFT JOIN table_name AS t_credits ON t_credits.client_id=t_debits.client_id
WHERE 
    t_debits.action_type='debit'
    AND t_credits.action_type='credit'
    AND balance!=0
GROUP BY t_debits.client_id, t_credits.client_id;

The result I am expecting is something like:

CLIENT_ID    DEBITS    CREDITS    BALANCE
1            1000      600        400
2            1000      1200       -200
4            1000      0          1000

I have no idea what else to try. Any help would be great.

3
  • What is your PRIMARY KEY? Commented May 23, 2014 at 10:26
  • AND balance!=0 doesn't work. You have to use having SUM(t_debits)-SUM(t_credits)<>0 Commented May 23, 2014 at 10:31
  • 1
    GROUP BY t_debits.client_id, t_credits.client_id; is not nesseary if t_debits.client_id = t_credits.client_id. You only need GROUP BY t_debits.client_id Commented May 23, 2014 at 10:32

3 Answers 3

22
DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(transaction_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,client_id INT NOT NULL
,action_type VARCHAR(12) NOT NULL
,action_amount INT NOT NULL
);

INSERT INTO my_table(client_id,action_type,action_amount) VALUES
(1            ,'debit',         1000),
(1            ,'credit',         100),
(1            ,'credit',         500),
(2            ,'debit',          1000),
(2            ,'credit',         1200),
(3            ,'debit',          1000),
(3            ,'credit',         1000),
(4            ,'debit',          1000);


SELECT client_id
     , SUM(COALESCE(CASE WHEN action_type = 'debit' THEN action_amount END,0)) total_debits
     , SUM(COALESCE(CASE WHEN action_type = 'credit' THEN action_amount END,0)) total_credits
     , SUM(COALESCE(CASE WHEN action_type = 'debit' THEN action_amount END,0)) 
     - SUM(COALESCE(CASE WHEN action_type = 'credit' THEN action_amount END,0)) balance 
  FROM my_table 
 GROUP  
    BY client_id
HAVING balance <> 0;


+-----------+--------------+---------------+---------+
| client_id | total_debits | total_credits | balance |
+-----------+--------------+---------------+---------+
|         1 |         1000 |           600 |     400 |
|         2 |         1000 |          1200 |    -200 |
|         4 |         1000 |             0 |    1000 |
+-----------+--------------+---------------+---------+
Sign up to request clarification or add additional context in comments.

7 Comments

+1 . . . I prefer this method because it uses a having clause instead of a subquery.
Me too - although I like the "ELSE 0" part of the other method.
. . This is your answer. You can add in the else 0 and remove the coalesce().
After taking a closer look I have decided to go for this one as the answer, with the modification that @GordonLinoff suggested. I prefer doing this without using a subquery.
@user2959229 . . . In other databases, it wouldn't make a difference but MySQL materializes subqueries (yuck!). Even in this case, it makes little difference, because the group by has to read and write the data multiple times. However, when using MySQL, I just think it is better form to avoid subqueries except when necessary.
|
4

You need to use case statement

select client_id, debits, credits, debits-credits as balance
from (SELECT 
client_id,
SUM(case when ACTION_TYPE='debit' then action_amount else 0 end) AS debits, 
SUM(case when ACTION_TYPE='credit' then action_amount else 0 end) AS credits
FROM categories 
GROUP BY client_id) a
where debits-credits<>0;

Fiddle

3 Comments

This appears to work correctly. Going to test to make double sure! Thanks.
Lemme know if there is any issue
This one did the job, but I've gone with the other answer that does not use a subquery.
1

USE THIS SMALLEST QUERY

        select CLIENT_ID,
                    sum(if(ACTION_TYPE='credit',ACTION_AMOUNT,0)) as credit,
                    sum(if(ACTION_TYPE='debit',ACTION_AMOUNT,0)) as debit,
                    sum(if(ACTION_TYPE='credit',ACTION_AMOUNT,-1*ACTION_AMOUNT)) as balance
        FROM YOUR_TABLE
        GROUP BY CLIENT_ID

2 Comments

If you could explain how your query works, it would make this a real answer.
This is not working SQL error: ERROR: function if(boolean, double precision, double precision) does not exist

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.