通过触发器更新多行

时间:2014-01-06 08:56:02

标签: mysql triggers

我已创建此触发器以更新发票金额。这是保存触发器的付款表。

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'

任何人都可以帮助纠正我在哪里以及我做错了什么?

1 个答案:

答案 0 :(得分:2)

<强>更新

修正查询:

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

请记住,应用程序逻辑在应用程序代码中更容易处理和维护,而不是在数据库触发器中。