我有一个带有表inventory
的MySQL数据库,其中设置了多个触发器以捕获第二个表inventory_history
中的更改。我更新了两个字段(包括单个查询和两个单独的查询),触发器始终只对两个字段中的一个字段起作用(qty
但不在last_sale
上)。
这是一个麻烦的问题:
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)
我无法重现这个问题:
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)
答案 1 :(得分: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;
此声明的问题在于,它不会捕获从NULL
到0
的值更改。它只捕获另一个值的值。所以我需要为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;
全世界都是对的。 :)