如何使用before insert触发器分配外键值

时间:2012-02-15 07:13:34

标签: mysql database triggers foreign-keys

我有这样的场景:

有两个表table1table2。如果提供了外键,则table1具有主键pkey并且table2现在在插入期间具有外键fkey,该值应按原样插入。否则,它必须使用某些计算从table1获取主键并确定要插入的外键。我该怎么办?

我正在使用MySql 5.0

修改

在我的方案中,table1包含结算明细,即table1包含帐单和要支付的总金额。客户支付一定数额的未结余额或将支付特定账单。我想做的是。如果我没有收到bill_idtable1中的主键和table2中的外键),我希望在table1中搜索到期的最旧帐单并扣除应付金额,并从结算订单中的下一个帐单中扣除剩余金额(如果有的话)。我想在数据库层而不是上层执行此操作。因此,当执行插入而没有外键值时,应该通过触发器检索并放置该值,或者直接插入该值。我如何实现这一目标?

使用此处提供的答案,我尝试了这个:

CREATE DEFINER=`root`@`localhost` TRIGGER `inflow_pay_done_insert` BEFORE INSERT ON `inflow_pay_done` FOR EACH ROW BEGIN
    DECLARE pkey INT;
    SET pkey = (SELECT bill_id from inflow_bills where payment_stat = 0 and rs_id = NEW.rs_id order by time_stamp limit 1);
    SET NEW.bill_id = IF(NEW.bill_id , NEW.bill_id , pkey);
    UPDATE raw_mat_sup rms SET rms.outstanding_bal_payable = rms.outstanding_bal_payable - NEW.amount where rms.rs_id = NEW.rs_id;
END|

当我尝试在inflow_pay_done中插入时,我收到以下错误:

/ * SQL错误(1048):列'bill_id'不能为null * /

1 个答案:

答案 0 :(得分:4)

您可以在BEFORE INSERT触发器中使用子查询...

DELIMITER |
DROP TRIGGER `inflow_pay_done_insert`|
CREATE TRIGGER `inflow_pay_done_insert` BEFORE INSERT ON `inflow_pay_done`
FOR EACH ROW
BEGIN
  UPDATE raw_mat_sup rms 
    SET rms.outstanding_bal_payable = rms.outstanding_bal_payable - NEW.amount 
    WHERE rms.rs_id = NEW.rs_id;
  NEW.bill_id = IF(NEW.bill_id, 
    /* if "bill_id" is provided in INSERT statement, use provided value */
    NEW.bill_id, 
    /* if not, query other table for the correct value */
    (  /* this subquery is just an example, put your own query here*/
       SELECT bill_id FROM inflow_bills 
       /* find customers newest bill based on newest date and customer id */
       WHERE payment_stat = 0 AND rs_id = NEW.rs_id
       ORDER BY time_stamp DESC LIMIT 1
    )
  );
END;
|
delimiter;

<强>更新

由于MySQL Bug,这仅在允许列为NULL并且列上没有约束( - &gt;外键)时才有效。原因是MySQL与其他DBMS不同,在执行BEFORE INSERT触发器之前检查约束,并有效地避免执行将纠正要插入的数据的触发器。

在MySQL的行为改变之前,唯一的解决方案是使用STORED PROCEDURE而不是普通INSERT。然后使用应插入的值调用存储过程。在该过程中,完成数据更正(如本例中:选择右bill_id),然后从存储过程中执行INSERT

更新II

这个错误似乎在5.7.1中得到修复。 Changelog说:

  

如果列声明为NOT NULL,则不允许插入   NULL进入列或将其更新为NULL。但是,这种约束   即使有一个BEFORE INSERT(或更新之前)也被强制执行   trigger)将列设置为非NULL值。现在约束   根据SQL标准在语句末尾检查。