插入时触发;代替A做B
Trigger on insert; instead of A do B
我有两个表:warehouse
和 inventory
:
CREATE TABLE warehouse (
bin VARCHAR(6) NOT NULL AUTO_INCREMENT,
qty INT
PRIMARY KEY(bin)
);
CREATE TABLE inventory (
item INT NOT NULL AUTO_INCREMENT,
name VARCHAR(10),
PRIMARY KEY(item)
);
我想设置一个触发器,以便 inventory
上的任何插入,如果该插入没有唯一名称,也将其添加到 warehouse
,否则适当增加 warehouse.qty
.
如果我要在 inventory
中插入一行:
INSERT INTO inventory
VALUES('', 'hammer");
inventory warehouse
----------------------------
item | name bin | qty
----------------------------
1 hammer 1 1
已添加 inventory
中的一行,但 warehouse
中也添加了一行。然后添加另一个唯一行:
INSERT INTO inventory
VALUES('', 'pliers");
inventory warehouse
----------------------------
item | name bin | qty
----------------------------
1 hammer 1 1
2 pliers 2 1
终于添加了第二个锤子。
INSERT INTO inventory
VALUES('', 'hammer");
inventory warehouse
----------------------------
item | name bin | qty
----------------------------
1 hammer 1 2
2 pliers 2 1
请注意,当第二次 'hammer' 插入发生时,没有向 inventory
添加新行,而是 warehouse
中的相关行增加了 qty
。
如何在 SQL 中创建此触发器?
...
- Some attributes do not apply to all data types. AUTO_INCREMENT applies only to integer and floating-point types. DEFAULT does not apply to the BLOB, TEXT, GEOMETRY, and JSON types.
...
CREATE TABLE warehouse (
bin VARCHAR(6) NOT NULL AUTO_INCREMENT, -- <- It's not possible
qty INT,
PRIMARY KEY(bin)
);
你可能有一些选择,有一些考虑:
- 如果
item
列必须严格按照顺序(AUTO_INCREMENT),可以在存储过程中封装INSERT
逻辑:
示例Rextester:
mysql> DROP PROCEDURE IF EXISTS `insert_inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `warehouse`, `inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `warehouse` (
-> `bin` VARCHAR(6) NOT NULL,
-> `qty` INT DEFAULT 1,
-> PRIMARY KEY(`bin`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `item` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(10),
-> PRIMARY KEY(`item`),
-> UNIQUE KEY(`name`)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TRIGGER `trg_ai_inventory` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> INSERT INTO `warehouse` (`bin`)
-> VALUES (NEW.`item`);
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE `insert_inventory`(`_name` VARCHAR(10))
-> BEGIN
-> DECLARE `_item` INT DEFAULT (SELECT `item`
-> FROM `inventory`
-> WHERE `name` = `_name`);
-> IF `_item` IS NULL THEN
-> INSERT INTO `inventory` (`name`)
-> VALUES (`_name`);
-> ELSE
-> UPDATE `warehouse`
-> SET `qty` = `qty` + 1
-> WHERE `bin` = `_item`;
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `insert_inventory`('hammer');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 1 |
+-----+------+
1 row in set (0.00 sec)
mysql> CALL `insert_inventory`('hammer');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
+-----+------+
1 row in set (0.00 sec)
mysql> CALL `insert_inventory`('pliers');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
| 2 | pliers |
+------+--------+
2 rows in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
| 2 | 1 |
+-----+------+
2 rows in set (0.00 sec)
- 如果
item
列不是必须严格按照顺序
(AUTO_INCREMENT), 你可以使用 14.2.5 INSERT Syntax::IGNORE or 14.2.5.3 INSERT ... ON DUPLICATE KEY UPDATE Syntax:
忽略(示例 Rextester):
mysql> DROP TABLE IF EXISTS `warehouse`, `inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `warehouse` (
-> `bin` VARCHAR(6) NOT NULL,
-> `qty` INT DEFAULT 1,
-> PRIMARY KEY(`bin`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `item` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(10),
-> PRIMARY KEY(`item`),
-> UNIQUE KEY(`name`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `trg_bi_inventory` BEFORE INSERT ON `inventory`
-> FOR EACH ROW
-> BEGIN
-> DECLARE `_item` INT DEFAULT (SELECT `item`
-> FROM `inventory`
-> WHERE `name` = NEW.`name`);
-> IF `_item` IS NOT NULL THEN
-> UPDATE `warehouse`
-> SET `qty` = `qty` + 1
-> WHERE `bin` = `_item`;
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CREATE TRIGGER `trg_ai_inventory` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> INSERT INTO `warehouse` (`bin`)
-> VALUES (NEW.`item`);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT IGNORE `inventory` (`name`)
-> VALUES ('hammer');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 1 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT IGNORE `inventory` (`name`)
-> VALUES ('hammer');
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT IGNORE `inventory` (`name`)
-> VALUES ('pliers');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
| 3 | pliers |
+------+--------+
2 rows in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
| 3 | 1 |
+-----+------+
2 rows in set (0.00 sec)
关于重复密钥更新(示例 Rextester):
mysql> DROP TABLE IF EXISTS `warehouse`, `inventory`;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE `warehouse` (
-> `bin` VARCHAR(6) NOT NULL,
-> `qty` INT DEFAULT 1,
-> PRIMARY KEY(`bin`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `item` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(10),
-> `count` INT DEFAULT 1,
-> PRIMARY KEY(`item`),
-> UNIQUE KEY(`name`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TRIGGER `trg_ai_inventory` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> INSERT INTO `warehouse` (`bin`)
-> VALUES (NEW.`item`);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TRIGGER `trg_au_inventory` AFTER UPDATE ON `inventory`
-> FOR EACH ROW
-> UPDATE `warehouse`
-> SET `qty` = `qty` + 1
-> WHERE `bin` = OLD.`item`;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `inventory` (`name`)
-> VALUES ('hammer')
-> ON DUPLICATE KEY UPDATE `count` = `count` + 1;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 1 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT INTO `inventory` (`name`)
-> VALUES ('hammer')
-> ON DUPLICATE KEY UPDATE `count` = `count` + 1;
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT INTO `inventory` (`name`)
-> VALUES ('pliers')
-> ON DUPLICATE KEY UPDATE `count` = `count` + 1;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
| 3 | pliers |
+------+--------+
2 rows in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
| 3 | 1 |
+-----+------+
2 rows in set (0.00 sec)
我有两个表:warehouse
和 inventory
:
CREATE TABLE warehouse (
bin VARCHAR(6) NOT NULL AUTO_INCREMENT,
qty INT
PRIMARY KEY(bin)
);
CREATE TABLE inventory (
item INT NOT NULL AUTO_INCREMENT,
name VARCHAR(10),
PRIMARY KEY(item)
);
我想设置一个触发器,以便 inventory
上的任何插入,如果该插入没有唯一名称,也将其添加到 warehouse
,否则适当增加 warehouse.qty
.
如果我要在 inventory
中插入一行:
INSERT INTO inventory
VALUES('', 'hammer");
inventory warehouse
----------------------------
item | name bin | qty
----------------------------
1 hammer 1 1
已添加 inventory
中的一行,但 warehouse
中也添加了一行。然后添加另一个唯一行:
INSERT INTO inventory
VALUES('', 'pliers");
inventory warehouse
----------------------------
item | name bin | qty
----------------------------
1 hammer 1 1
2 pliers 2 1
终于添加了第二个锤子。
INSERT INTO inventory
VALUES('', 'hammer");
inventory warehouse
----------------------------
item | name bin | qty
----------------------------
1 hammer 1 2
2 pliers 2 1
请注意,当第二次 'hammer' 插入发生时,没有向 inventory
添加新行,而是 warehouse
中的相关行增加了 qty
。
如何在 SQL 中创建此触发器?
...
- Some attributes do not apply to all data types. AUTO_INCREMENT applies only to integer and floating-point types. DEFAULT does not apply to the BLOB, TEXT, GEOMETRY, and JSON types.
...
CREATE TABLE warehouse (
bin VARCHAR(6) NOT NULL AUTO_INCREMENT, -- <- It's not possible
qty INT,
PRIMARY KEY(bin)
);
你可能有一些选择,有一些考虑:
- 如果
item
列必须严格按照顺序(AUTO_INCREMENT),可以在存储过程中封装INSERT
逻辑:
示例Rextester:
mysql> DROP PROCEDURE IF EXISTS `insert_inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `warehouse`, `inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `warehouse` (
-> `bin` VARCHAR(6) NOT NULL,
-> `qty` INT DEFAULT 1,
-> PRIMARY KEY(`bin`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `item` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(10),
-> PRIMARY KEY(`item`),
-> UNIQUE KEY(`name`)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TRIGGER `trg_ai_inventory` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> INSERT INTO `warehouse` (`bin`)
-> VALUES (NEW.`item`);
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE PROCEDURE `insert_inventory`(`_name` VARCHAR(10))
-> BEGIN
-> DECLARE `_item` INT DEFAULT (SELECT `item`
-> FROM `inventory`
-> WHERE `name` = `_name`);
-> IF `_item` IS NULL THEN
-> INSERT INTO `inventory` (`name`)
-> VALUES (`_name`);
-> ELSE
-> UPDATE `warehouse`
-> SET `qty` = `qty` + 1
-> WHERE `bin` = `_item`;
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CALL `insert_inventory`('hammer');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 1 |
+-----+------+
1 row in set (0.00 sec)
mysql> CALL `insert_inventory`('hammer');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
+-----+------+
1 row in set (0.00 sec)
mysql> CALL `insert_inventory`('pliers');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
| 2 | pliers |
+------+--------+
2 rows in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
| 2 | 1 |
+-----+------+
2 rows in set (0.00 sec)
- 如果
item
列不是必须严格按照顺序 (AUTO_INCREMENT), 你可以使用 14.2.5 INSERT Syntax::IGNORE or 14.2.5.3 INSERT ... ON DUPLICATE KEY UPDATE Syntax:
忽略(示例 Rextester):
mysql> DROP TABLE IF EXISTS `warehouse`, `inventory`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `warehouse` (
-> `bin` VARCHAR(6) NOT NULL,
-> `qty` INT DEFAULT 1,
-> PRIMARY KEY(`bin`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `item` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(10),
-> PRIMARY KEY(`item`),
-> UNIQUE KEY(`name`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER //
mysql> CREATE TRIGGER `trg_bi_inventory` BEFORE INSERT ON `inventory`
-> FOR EACH ROW
-> BEGIN
-> DECLARE `_item` INT DEFAULT (SELECT `item`
-> FROM `inventory`
-> WHERE `name` = NEW.`name`);
-> IF `_item` IS NOT NULL THEN
-> UPDATE `warehouse`
-> SET `qty` = `qty` + 1
-> WHERE `bin` = `_item`;
-> END IF;
-> END//
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
mysql> CREATE TRIGGER `trg_ai_inventory` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> INSERT INTO `warehouse` (`bin`)
-> VALUES (NEW.`item`);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT IGNORE `inventory` (`name`)
-> VALUES ('hammer');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 1 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT IGNORE `inventory` (`name`)
-> VALUES ('hammer');
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT IGNORE `inventory` (`name`)
-> VALUES ('pliers');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
| 3 | pliers |
+------+--------+
2 rows in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
| 3 | 1 |
+-----+------+
2 rows in set (0.00 sec)
关于重复密钥更新(示例 Rextester):
mysql> DROP TABLE IF EXISTS `warehouse`, `inventory`;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE `warehouse` (
-> `bin` VARCHAR(6) NOT NULL,
-> `qty` INT DEFAULT 1,
-> PRIMARY KEY(`bin`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `inventory` (
-> `item` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
-> `name` VARCHAR(10),
-> `count` INT DEFAULT 1,
-> PRIMARY KEY(`item`),
-> UNIQUE KEY(`name`)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TRIGGER `trg_ai_inventory` AFTER INSERT ON `inventory`
-> FOR EACH ROW
-> INSERT INTO `warehouse` (`bin`)
-> VALUES (NEW.`item`);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TRIGGER `trg_au_inventory` AFTER UPDATE ON `inventory`
-> FOR EACH ROW
-> UPDATE `warehouse`
-> SET `qty` = `qty` + 1
-> WHERE `bin` = OLD.`item`;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO `inventory` (`name`)
-> VALUES ('hammer')
-> ON DUPLICATE KEY UPDATE `count` = `count` + 1;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 1 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT INTO `inventory` (`name`)
-> VALUES ('hammer')
-> ON DUPLICATE KEY UPDATE `count` = `count` + 1;
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
+------+--------+
1 row in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
+-----+------+
1 row in set (0.00 sec)
mysql> INSERT INTO `inventory` (`name`)
-> VALUES ('pliers')
-> ON DUPLICATE KEY UPDATE `count` = `count` + 1;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT `item`, `name`
-> FROM `inventory`;
+------+--------+
| item | name |
+------+--------+
| 1 | hammer |
| 3 | pliers |
+------+--------+
2 rows in set (0.00 sec)
mysql> SELECT `bin`, `qty`
-> FROM `warehouse`;
+-----+------+
| bin | qty |
+-----+------+
| 1 | 2 |
| 3 | 1 |
+-----+------+
2 rows in set (0.00 sec)