Felipe
Felipe

Reputation: 35

MySql Query Credits And Debits From Same Table

I have a MySql table to control debits and credits. And it looks like this

id | status | type  | amount | value | expiration | parent_id | company_id |
---|--------|------ |--------|-------|------------|-----------|------------|
1  |    1   |credit | 46     | 42.00 | 2018-04-01 | 0         | 1          |
2  |    1   |credit | 33     | 194.00| 2017-07-07 | 0         | 1          |
3  |    1   |credit | 49     | 17.00 | 2016-11-11 | 0         | 1          |
4  |    1   |debit  | 1      | NULL  | NULL       | 1         | 1          |
5  |    1   |debit  | 1      | NULL  | NULL       | 1         | 1          |
6  |    1   |debit  | 1      | NULL  | NULL       | 2         | 1          |
7  |    1   |debit  | 1      | NULL  | NULL       | 2         | 1          |
8  |    1   |debit  | 1      | NULL  | NULL       | 2         | 1          |
9  |    1   |debit  | 1      | NULL  | NULL       | 2         | 1          |
10 |    1   |debit  | 1      | NULL  | NULL       | 3         | 1          |

And I want to retrieve how many credits one have right now.

Sum all debits that has status = 1 for each parent credit that has status = 1 AND expiration > NOW()

And then subtract from it's parent credit

In this scenario I should get something like this

Total Credits = (46 - 2) + (33 - 4)

Where I got so far is

SELECT SUM(amount) as tot_debit 
FROM credits
WHERE company_id = 1 
      AND status = 1 
      AND type = 'debit' 
      AND parent_id IN (SELECT id
                         FROM credits 
                         WHERE company_id = 1 
                           AND status = 1 
                           AND expiration > NOW() 
                           AND type = 'credit') 
GROUP BY parent_id

Any ideas on how to get this working?

Thanks

Upvotes: 1

Views: 1003

Answers (3)

Thorsten Kettner
Thorsten Kettner

Reputation: 95101

As you have both credits and their debits in one table (a design I would not have recommended) the quickest way here is probably aggregation:

select sum(total)
from
(
  select 
    sum(case when type = 'credit' then value else -value end) as total
  from mytable
  where company_id = 1
  and status = 1
  group by case when type = 'credit' then id else parent_id end -- group by credit ID
  having sum(type = 'credit' and expiration > now()) > 0
) total_per_credit;

The HAVING clause makes use of true = 1 / false = 0 in MySQL. (In other DBMS you'd use a CASE construct.)

Upvotes: 0

Stefano Zanini
Stefano Zanini

Reputation: 5926

You should use a self left join so that each record is matched to its parent (if exists) and filter out the expired records. Then with a conditional sum you can add the credits and subtract the debits.

SELECT  SUM(CASE WHEN type = 'credit' THEN amount ELSE amount * -1 END) AS total
FROM    credits t1
LEFT JOIN
        credits t2
ON      t1.parent_id = t2.id AND
        t2.expiration > NOW()
WHERE   t1.company_id = 1 AND 
        t1.status = 1 AND
        t1.expiration > NOW()

Upvotes: 0

Giorgos Betsos
Giorgos Betsos

Reputation: 72235

You can use correlation to get at the expected result:

SELECT SUM(amount) 
       -
       COALESCE((SELECT SUM(amount)
                 FROM credits AS c2
                 WHERE company_id = 1 AND status = 1 AND 
                       type = 'debit' AND
                       c2.parent_id = c1.id), 0)
FROM credits AS c1
WHERE company_id = 1 AND status = 1 AND 
      type = 'credit' AND expiration > NOW();

Demo here

Upvotes: 1

Related Questions