This is an UNPIVOT problem.To get the sum of credit items and the sum of debit items you can use a SUM
of a CASE
statement. To show that, we need a table first:
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE invoice_items
(`invoice_item_id` int, `invoice_set_id` varchar(3), `credit_debit` varchar(6), `amount` int)
;
INSERT INTO invoice_items
(`invoice_item_id`, `invoice_set_id`, `credit_debit`, `amount`)
VALUES
(62, 'a22', 'debit', 15.00),
(63, 'a22', 'debit', 8.00),
(64, 'a22', 'credit', 23.00),
(65, 'b23', 'debit', 44.00),
(66, 'c55', 'debit', 15.00),
(67, 'c55', 'debit', 2.00),
(67, 'c55', 'credit', 8.00)
;
Now you can combine SUM
and CASE
like this:
Query 1:
SELECT invoice_set_id,
SUM(CASE WHEN credit_debit = 'debit' THEN amount END) AS debit_amount,
SUM(CASE WHEN credit_debit = 'credit' THEN amount END) AS credit_amount
FROM invoice_items
GROUP BY invoice_set_id;
Results:
| INVOICE_SET_ID | DEBIT_AMOUNT | CREDIT_AMOUNT |
|----------------|--------------|---------------|
| a22 | 23 | 23 |
| b23 | 44 | (null) |
| c55 | 17 | 8 |
From here it is fairly simple to filter out the unwanted rows. We just need to wrap the two sums in COALESCE
statements to turn NULL
into 0:
Query 2:
SELECT invoice_set_id
FROM(
SELECT invoice_set_id,
SUM(CASE WHEN credit_debit = 'debit' THEN amount END) AS debit_amount,
SUM(CASE WHEN credit_debit = 'credit' THEN amount END) AS credit_amount
FROM invoice_items
GROUP BY invoice_set_id
)X
WHERE COALESCE(debit_amount,0) > COALESCE(credit_amount,0);
Results:
| INVOICE_SET_ID |
|----------------|
| b23 |
| c55 |
If your actual problem is as simple as your example and you do not need the intermediate values for anything else, you can get the result also by just changing the sign of the amount based on the credit_debit
value before calculating the sum. That would look like this:
Query 3:
SELECT invoice_set_id
FROM invoice_items
GROUP BY invoice_set_id
HAVING SUM(CASE WHEN credit_debit = 'debit' THEN amount ELSE -amount END)>0;
Results:
| INVOICE_SET_ID |
|----------------|
| b23 |
| c55 |
Best Answer
Without a doubt, I would rule out triggers and strictly stay with transactions.
Triggers are, by nature, stored procedures. Their actions are virtually hard to roll back. Even if all underlying tables are InnoDB, you will experience a proportional volume of shared row locks and annoying intermittency from exclusive row locks. Such would be the case if triggers were manipulating tables with INSERTs and UPDATEs being stagnated to perform heavy duty MVCC inside each call to a trigger.
Combine this with the fact that proper data validation protocols are not implemented in MySQL's Stored Procedure Language. Business Intelligence is OK to have contained in a database provided the Stored Procedure Language can handle a transactional environment. As a MySQL DBA, I have to honestly say that such is not the case with MySQL. Oracle (PL/SQL), PostgreSQL (PL/pgSQL), and SQL Server (T-SQL) have this edge over MySQL.
Concerning transactions, MySQL has InnoDB as its main ACID-compliant storage engine (Deafult storage engine in MySQL 5.5). It has excellent crash recovery and obeys the ACID compliance protocols.
I would choose transacitons over triggers every single time.