2014-01-06 3 views
1

Я создал этот триггер, чтобы обновить количество счетов-фактур. Это таблица платежей, которая содержит триггер.UPDATE mulitiple rows via trigger

ci_payments

CREATE TABLE `ci_payments` ( 
     `payment_id` bigint(10) NOT NULL AUTO_INCREMENT, 
     `customer_id` bigint(10) NOT NULL, 
     `payment_method` varchar(15) NOT NULL, 
     `receipt_number` varchar(50) NOT NULL, 
     `cheque_number` varchar(50) NOT NULL, 
     `amount` decimal(18,2) NOT NULL, 
     `payment_on` datetime NOT NULL, 
     `payment_note` mediumtext NOT NULL, 
     `current_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
     PRIMARY KEY (`payment_id`), KEY `invoice_id` (`customer_id`) 
) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 

Это Inovice таблицы и данные:

Invoice Table

Например, возьмем Customer ID: 8, который имеет два счета, которые paid_amount 0.00; Я пытаюсь обновить сумму счета-фактуры через триггер по таблице оплаты.

Пусть говорят Клиент заплатил 400.00, поэтому я хочу, чтобы обновить первый счет в paid и второй как partial с paid_amount;

Это триггер я создал

DELIMITER $$ 

CREATE TRIGGER uni_payment_updater AFTER INSERT ON ci_payments FOR EACH ROW BEGIN 

DECLARE done INT DEFAULT FALSE; 
DECLARE amt_diff, t_amount DECIMAL(9,2); 
DECLARE inv_id INTEGER; 
DECLARE cur CURSOR FOR select total_amount, invoice_id from ci_invoices where customer_id = new.customer_id and (status = "unpaid" or status = "partial") order by invoice_id asc; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 

SET @uni_paid_amount := NEW.amount; 

OPEN cur; 
    ins_loop: LOOP 
     FETCH cur INTO t_amount, inv_id; 

      IF done THEN 
       LEAVE ins_loop; 
      END IF; 

      SET amt_diff = NEW.amount - t_total; 

      IF amt_diff > 0.00 THEN 
       UPDATE ci_invoices set paid_amount = amt_diff where invoice_id = inv_id; 
      END IF; 
    END LOOP; 
CLOSE cur; 


END; 

$$ 
DELIMITER ; 

Но я получаю эту ошибку
Unknown column 'uni_paid_amount' in 'field list'

Любой пожалуйста, помогите исправить, где и что я делаю неправильно?

+0

Я думаю, что вы забыли @. Попробуйте SET amt_diff = @uni_paid_amount - t_total; –

+0

@KayNelson Я попробовал как 'SET amt_diff = @uni_paid_amount - @t_total ;, но я думаю, что' @ 'игнорирует предупреждения. Но теперь результат не обновлен в таблице 'ci_invoice' –

+0

Что делать, если вы пытаетесь использовать' NEW.amount' вместо переменной? –

ответ

2

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 | 
+----+-------------+--------------+-------------+---------+ 

Имейте в виду, однако, что логика приложения проще в обращении и обслуживании в коде приложения, а не в триггерах базы данных.

+0

Я попытался с помощью триггера с количеством '200' и ​​его не работал, как я ожидал. Он обновляет значения в соответствии с вашим примером –

+0

Он работает только в том случае, если мы вставляем значение выше, чем платная сумма, я пробовал с значением '400' и ​​его работой, но не с' 200', если я попытался использовать 200, paid_amount' должен быть 103,75 для первого счета-фактуры как статус частичного и пропустить второй вариант, потому что прикладная сумма уже добавлена ​​в первый счет-фактуру. –

+0

@jogesh_pi Исправлен мой запрос. См. Отредактированный ответ, теперь он работает в обоих случаях. – fancyPants