2017-02-22 85 views
0

我有一个MySQL数据库,其中有一个表inventory,其中设置了多个触发器来捕获第二个表inventory_history中的更改。我正在更新两个字段(包括单个查询和两个单独的查询),并且触发器始终只在两个字段中的一个(qty,但不在last_sale)上工作。MySQL触发器在同一个表中的一个字段而不是第二个字段上工作

这里是麻烦的查询:

UPDATE inventory SET last_sale = 321, qty = 0 WHERE id = 123; 

或者,这些查询组合不工作,要么:

UPDATE inventory SET last_sale = 321 WHERE id = 123; 
UPDATE inventory SET qty = 0 WHERE id = 123; 

这里是表结构和触发:

CREATE TABLE `inventory` (
    `serial_no` varchar(255) DEFAULT NULL, 
    `qty` mediumint(9) DEFAULT NULL, 
    `partid` mediumint(9) unsigned DEFAULT NULL, 
    `last_sale` mediumint(9) unsigned DEFAULT NULL, 
    `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 
    `id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`), 
    KEY `partid` (`partid`), 
    KEY `date_created` (`date_created`), 
    KEY `last_sale` (`last_sale`), 
    KEY `last_rma` (`last_return`), 
    KEY `last_purchase` (`last_purchase`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

CREATE TABLE `inventory_history` (
    `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `inventory_id` mediumint(9) unsigned NOT NULL, 
    `field_changed` enum('serial_no','qty','partid','last_sale','new') NOT NULL, 
    `changed_from` varchar(255) NOT NULL, 
    KEY `inventory_id` (`inventory_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

CREATE TRIGGER `inv_new` AFTER INSERT ON `inventory` 
FOR EACH ROW BEGIN 
    SET 
    @id = NEW.id, 
    @userid = NEW.userid, 
    @date = now(); 

    INSERT INTO inventory_history VALUES (@date,@userid, @id, 'new', 'new'); 
END 
// 
DELIMITER ; 
DROP TRIGGER IF EXISTS `inv_update`; 
DELIMITER // 
CREATE TRIGGER `inv_update` AFTER UPDATE ON `inventory` 
FOR EACH ROW BEGIN 
    SET @userid = OLD.userid; 
    SET @inv_id = OLD.id; 

    IF (OLD.serial_no <> NEW.serial_no) THEN 
    INSERT INTO inventory_history VALUES (now(), @userid, @inv_id, 'serial_no', OLD.serial_no); 
    END IF; 

    IF (OLD.qty <> NEW.qty) THEN 
    INSERT INTO inventory_history VALUES (now(), @userid, @inv_id, 'qty', OLD.qty); 
    END IF; 

    IF (OLD.partid <> NEW.partid) THEN 
    INSERT INTO inventory_history VALUES (now(), @userid, @inv_id, 'partid', OLD.partid); 
    END IF; 

    IF (OLD.last_sale <> NEW.last_sale) THEN 
    INSERT INTO inventory_history VALUES (now(), @userid, @inv_id, 'last_sale', OLD.last_sale); 
    END IF; 
END 
// 
DELIMITER ; 

再次,qty触发器工作,但last_sale不。

+0

奇怪,你的代码似乎没有问题,要自己尝试 –

回答

0

以后的日子里,原来是一个简单而深刻的解释(是不是总是?)。

我上面使用的触发声明是:

IF (OLD.last_sale <> NEW.last_sale) THEN 
    INSERT INTO inventory_history VALUES (now(), @userid, @inv_id, 'last_sale', OLD.last_sale); 
    END IF; 

这个说法的问题在于,它并不能捕捉到的数值变化从NULL0,例如。它只捕获另一个值的值。所以,我需要添加第二个声明了NULL场景:

IF (OLD.last_sale IS NULL AND NEW.last_sale IS NOT NULL) THEN 
    INSERT INTO inventory_history VALUES (now(), @userid, @inv_id, 'last_sale', OLD.last_sale); 
    END IF; 

和所有的世界是正确的。 :)

0

我不能重现该问题:

mysql> DROP TABLE IF EXISTS `inventory_history`, `inventory`; 
Query OK, 0 rows affected (0.00 sec) 

mysql> CREATE TABLE `inventory` (
    -> `serial_no` varchar(255) DEFAULT NULL, 
    -> `qty` mediumint(9) DEFAULT NULL, 
    -> `partid` mediumint(9) unsigned DEFAULT NULL, 
    -> `last_sale` mediumint(9) unsigned DEFAULT NULL, 
    -> `date_created` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 
    -> `id` mediumint(9) unsigned NOT NULL AUTO_INCREMENT, 
    -> PRIMARY KEY (`id`), 
    -> KEY `partid` (`partid`), 
    -> KEY `date_created` (`date_created`), 
    -> KEY `last_sale` (`last_sale`) 
    ->) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
Query OK, 0 rows affected (0.00 sec) 

mysql> CREATE TABLE `inventory_history` (
    -> `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    -> `inventory_id` mediumint(9) unsigned NOT NULL, 
    -> `field_changed` enum('serial_no', 'qty', 'partid', 'last_sale', 'new') NOT NULL, 
    -> `changed_from` varchar(255) NOT NULL, 
    -> KEY `inventory_id` (`inventory_id`) 
    ->) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
Query OK, 0 rows affected (0.01 sec) 

mysql> DELIMITER // 

mysql> CREATE TRIGGER `inv_new` AFTER INSERT ON `inventory` 
    -> FOR EACH ROW 
    -> BEGIN 
    -> DECLARE `_id` MEDIUMINT UNSIGNED DEFAULT NEW.`id`; 
    -> DECLARE `_date` TIMESTAMP DEFAULT NOW(); 
    -> INSERT INTO `inventory_history` VALUES (`_date`, `_id`, 'new', 'new'); 
    -> END// 
Query OK, 0 rows affected (0.00 sec) 

mysql> DELIMITER ; 

mysql> DROP TRIGGER IF EXISTS `inv_update`; 
Query OK, 0 rows affected, 1 warning (0.00 sec) 

mysql> DELIMITER // 

mysql> CREATE TRIGGER `inv_update` AFTER UPDATE ON `inventory` 
    -> FOR EACH ROW 
    -> BEGIN 
    -> DECLARE `_inv_id` MEDIUMINT UNSIGNED DEFAULT OLD.`id`; 
    -> 
    -> IF (OLD.`serial_no` <> NEW.`serial_no`) THEN 
    ->  INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'serial_no', OLD.`serial_no`); 
    -> END IF; 
    -> 
    -> IF (OLD.`qty` <> NEW.`qty`) THEN 
    ->  INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'qty', OLD.`qty`); 
    -> END IF; 
    -> 
    -> IF (OLD.`partid` <> NEW.`partid`) THEN 
    ->  INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'partid', OLD.`partid`); 
    -> END IF; 
    -> 
    -> IF (OLD.`last_sale` <> NEW.`last_sale`) THEN 
    ->  INSERT INTO `inventory_history` VALUES (NOW(), `_inv_id`, 'last_sale', OLD.`last_sale`); 
    -> END IF; 
    -> END// 
Query OK, 0 rows affected (0.00 sec) 

mysql> DELIMITER ; 

mysql> INSERT INTO `inventory` 
    -> (`serial_no`, `qty`, `partid`, `last_sale`) 
    -> VALUES 
    -> ('1', 0, 0, 321); 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT 
    -> `serial_no`, 
    -> `qty`, 
    -> `partid`, 
    -> `last_sale`, 
    -> `date_created`, 
    -> `id` 
    -> FROM 
    -> `inventory`; 
+-----------+------+--------+-----------+---------------------+----+ 
| serial_no | qty | partid | last_sale | date_created  | id | 
+-----------+------+--------+-----------+---------------------+----+ 
| 1   | 0 |  0 |  321 | 2016-11-15 00:00:51 | 1 | 
+-----------+------+--------+-----------+---------------------+----+ 
1 row in set (0.00 sec) 

mysql> SELECT 
    -> `date`, 
    -> `inventory_id`, 
    -> `field_changed`, 
    -> `changed_from` 
    -> FROM 
    -> `inventory_history`; 
+---------------------+--------------+---------------+--------------+ 
| date    | inventory_id | field_changed | changed_from | 
+---------------------+--------------+---------------+--------------+ 
| 2016-11-15 00:00:51 |   1 | new   | new   | 
+---------------------+--------------+---------------+--------------+ 
1 row in set (0.00 sec) 

mysql> UPDATE `inventory` 
    -> SET `last_sale` = 0, `qty` = 321 
    -> WHERE `id` = 1; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

mysql> SELECT 
    -> `date`, 
    -> `inventory_id`, 
    -> `field_changed`, 
    -> `changed_from` 
    -> FROM 
    -> `inventory_history`; 
+---------------------+--------------+---------------+--------------+ 
| date    | inventory_id | field_changed | changed_from | 
+---------------------+--------------+---------------+--------------+ 
| 2016-11-15 00:00:51 |   1 | new   | new   | 
| 2016-11-15 00:00:51 |   1 | qty   | 0   | 
| 2016-11-15 00:00:51 |   1 | last_sale  | 321   | 
+---------------------+--------------+---------------+--------------+ 
3 rows in set (0.00 sec) 

mysql> SELECT 
    -> `serial_no`, 
    -> `qty`, 
    -> `partid`, 
    -> `last_sale`, 
    -> `date_created`, 
    -> `id` 
    -> FROM 
    -> `inventory`; 
+-----------+------+--------+-----------+---------------------+----+ 
| serial_no | qty | partid | last_sale | date_created  | id | 
+-----------+------+--------+-----------+---------------------+----+ 
| 1   | 321 |  0 |   0 | 2016-11-15 00:00:51 | 1 | 
+-----------+------+--------+-----------+---------------------+----+ 
1 row in set (0.00 sec) 
相关问题