2014-01-06 67 views
1

我已創建此觸發器來更新發票金額。這是支付觸發器的支付表。通過觸發器更新多個行

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

例如採取誰擁有已paid_amount 0.00兩張發票的Customer ID: 8; 我正試圖通過支付表上的觸發器更新發票金額。

假設客戶支付400.00所以我想更新第一張發票paid和第二partialpaid_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) 

原來的答覆:

你根本不需要觸發器,更不用說光標了(我總是儘量避免使用這些觸發器)。您知道您剛剛插入付款表的customer_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