UPDATE:
Фиксированный запрос:
set @paid = 200;
update invoice i
set
i.paid_amount = if(@paid <= total_amount, @paid, total_amount),
i.status = case when paid_amount = 0 then 'unpaid' when total_amount = paid_amount then 'paid' when paid_amount > 0 and paid_amount < total_amount then 'partial' else 'wtf' end,
i.id = if(@paid := if(@paid <= total_amount, 0, @paid - total_amount), i.id, i.id)
where i.customer_id = 16
order by id /*or whatever columns determines the order of the invoices*/
;
Пробовали со следующим, и он работает в настоящее время:
mysql> drop table if exists invoice;
Query OK, 0 rows affected (0.00 sec)
mysql> create table invoice (
-> id int auto_increment primary key,
-> customer_id int,
-> total_amount decimal(10,2),
-> paid_amount decimal(10,2) default 0,
-> status varchar(50) default 'unpaid'
->);
Query OK, 0 rows affected (0.06 sec)
mysql>
mysql> insert into invoice (customer_id, total_amount) values
-> (3, 0),
-> (8, 303.75),
-> (8, 200.00),
-> (16, 303.75),
-> (16, 200.00);
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql>
mysql> select * from invoice;
+----+-------------+--------------+-------------+--------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+--------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 0.00 | unpaid |
| 3 | 8 | 200.00 | 0.00 | unpaid |
| 4 | 16 | 303.75 | 0.00 | unpaid |
| 5 | 16 | 200.00 | 0.00 | unpaid |
+----+-------------+--------------+-------------+--------+
5 rows in set (0.01 sec)
mysql>
mysql>
mysql> set @paid = 400;
Query OK, 0 rows affected (0.00 sec)
mysql> update invoice i
-> set
-> i.paid_amount = if(@paid <= total_amount, @paid, total_amount),
-> i.status = case when paid_amount = 0 then 'unpaid' when total_amount = paid_amount then 'paid' when paid_amount > 0 and paid_amount < total_amount then 'partial' else 'wtf' end,
-> i.id = if(@paid := if(@paid <= total_amount, 0, @paid - total_amount), i.id, i.id)
-> where i.customer_id = 8
-> order by id /*or whatever columns determines the order of the invoices*/
-> ;
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql>
mysql> select * from invoice;
+----+-------------+--------------+-------------+---------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+---------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 303.75 | paid |
| 3 | 8 | 200.00 | 96.25 | partial |
| 4 | 16 | 303.75 | 0.00 | unpaid |
| 5 | 16 | 200.00 | 0.00 | unpaid |
+----+-------------+--------------+-------------+---------+
5 rows in set (0.00 sec)
mysql>
mysql> set @paid = 200;
Query OK, 0 rows affected (0.00 sec)
mysql> update invoice i
-> set
-> i.paid_amount = if(@paid <= total_amount, @paid, total_amount),
-> i.status = case when paid_amount = 0 then 'unpaid' when total_amount = paid_amount then 'paid' when paid_amount > 0 and paid_amount < total_amount then 'partial' else 'wtf' end,
-> i.id = if(@paid := if(@paid <= total_amount, 0, @paid - total_amount), i.id, i.id)
-> where i.customer_id = 16
-> order by id /*or whatever columns determines the order of the invoices*/
-> ;
Query OK, 1 row affected (0.00 sec)
Rows matched: 2 Changed: 1 Warnings: 0
mysql>
mysql> select * from invoice;
+----+-------------+--------------+-------------+---------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+---------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 303.75 | paid |
| 3 | 8 | 200.00 | 96.25 | partial |
| 4 | 16 | 303.75 | 200.00 | partial |
| 5 | 16 | 200.00 | 0.00 | unpaid |
+----+-------------+--------------+-------------+---------+
5 rows in set (0.00 sec)
Оригинальный ответ:
Вам вообще не нужен триггер, не говоря уже о курсоре (я всегда стараюсь избегать их любой ценой). Вы знаете client_id, который вы только что вставили в свою таблицу платежей. Затем запустите это заявление обновления после вставки.
/*table serving as example*/
drop table if exists invoice;
create table invoice (
id int auto_increment primary key,
customer_id int,
total_amount decimal(10,2),
paid_amount decimal(10,2) default 0,
status varchar(50) default 'unpaid'
);
/*sample data*/
insert into invoice (customer_id, total_amount) values
(3, 0),
(8, 303.75),
(8, 200.00);
select * from invoice;
+----+-------------+--------------+-------------+--------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+--------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 0.00 | unpaid |
| 3 | 8 | 200.00 | 0.00 | unpaid |
+----+-------------+--------------+-------------+--------+
set @paid = 400;
update invoice i
set
i.paid_amount = if(@paid - total_amount >= 0, total_amount, total_amount - @paid),
i.status = if(@paid - total_amount >= 0, 'paid', 'partial'),
i.id = if(@paid := @paid - total_amount, i.id, i.id)
where i.customer_id = 8
order by id /*or whatever columns determines the order of the invoices*/
;
select * from invoice;
+----+-------------+--------------+-------------+---------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+---------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 303.75 | paid |
| 3 | 8 | 200.00 | 103.75 | partial |
+----+-------------+--------------+-------------+---------+
Если вы настаиваете на использовании триггера, вот тот же пример с триггером:
drop table if exists invoice;
create table invoice (
id int auto_increment primary key,
customer_id int,
total_amount decimal(10,2),
paid_amount decimal(10,2) default 0,
status varchar(50) default 'unpaid'
);
insert into invoice (customer_id, total_amount) values
(3, 0),
(8, 303.75),
(8, 200.00);
drop table if exists payment;
create table payment (
id int auto_increment primary key,
customer_id int,
amount decimal(10,2)
);
delimiter $$
create trigger pay after insert on payment for each row
begin
set @paid = new.amount;
update invoice i
set
i.paid_amount = if(@paid - total_amount >= 0, total_amount, total_amount - @paid),
i.status = if(@paid - total_amount >= 0, 'paid', 'partial'),
i.id = if(@paid := @paid - total_amount, i.id, i.id)
where i.customer_id = new.customer_id
order by id;
end $$
delimiter ;
select * from invoice;
+----+-------------+--------------+-------------+--------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+--------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 0.00 | unpaid |
| 3 | 8 | 200.00 | 0.00 | unpaid |
+----+-------------+--------------+-------------+--------+
insert into payment (customer_id, amount) values (8, 400);
select * from invoice;
+----+-------------+--------------+-------------+---------+
| id | customer_id | total_amount | paid_amount | status |
+----+-------------+--------------+-------------+---------+
| 1 | 3 | 0.00 | 0.00 | unpaid |
| 2 | 8 | 303.75 | 303.75 | paid |
| 3 | 8 | 200.00 | 103.75 | partial |
+----+-------------+--------------+-------------+---------+
Имейте в виду, однако, что логика приложения проще в обращении и обслуживании в коде приложения, а не в триггерах базы данных.
Я думаю, что вы забыли @. Попробуйте SET amt_diff = @uni_paid_amount - t_total; –
@KayNelson Я попробовал как 'SET amt_diff = @uni_paid_amount - @t_total ;, но я думаю, что' @ 'игнорирует предупреждения. Но теперь результат не обновлен в таблице 'ci_invoice' –
Что делать, если вы пытаетесь использовать' NEW.amount' вместо переменной? –