Reputation: 35
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
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
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
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();
Upvotes: 1