我有一个表,它有一个复合主键id
和code
,还有一个value
。
CREATE TABLE `code_detail` (
`id` int(11) NOT NULL,
`code` varchar(6) NOT NULL,
`value` float DEFAULT NULL,
PRIMARY KEY (`id`,`code`),
CONSTRAINT `code_detail_ibfk_1` FOREIGN KEY (`id`) REFERENCES `code_assignment` (`id`),
CONSTRAINT `code_detail_ibfk_2` FOREIGN KEY (`code`) REFERENCES `code` (`code`)
)
看起来...
| id|代码|价值|
| - -----|- -----|- -----|
| 1|一个|三十|
| 1| B|七十|
| 2| C类|五十|
| 2| D级|五十|
目标是用新的代码和值覆盖where id = 2
。在此过程中,删除旧记录。
| id|代码|价值|
| - -----|- -----|- -----|
| 1|一个|三十|
| 1| B|七十|
| 2| E级|四十|
| 2| F型|六十|
当前,insert语句看起来像
INSERT INTO code_detail
(id, code, value)
VALUES ((2, 'E', 50), (2, 'F', 50))
ON DUPLICATE KEY UPDATE
value = VALUES(value)
您可能会注意到,在此之后,生成的表将是
| id|代码|价值|
| - -----|- -----|- -----|
| 1|一个|三十|
| 1| B|七十|
| 2| C类|五十|
| 2| D级|五十|
| 2| E级|四十|
| 2| F型|六十|
这是不期望的行为。应删除代码为C
和D
的记录。
我尝试创建一个触发器来检查id = 2
的旧行中的代码是否是新代码((2, 'D', 50), (2, 'E', 50))
的子集
DELIMITER $$
CREATE TRIGGER after_code_update
AFTER INSERT ON code_detail
FOR EACH ROW
BEGIN
IF old.id = new.id AND old.code NOT IN (VALUES(new.code)) THEN
CALL STORED_PROCEDURE(old.id, old.code);
END IF;
END$$
DELIMITER ;
这会引发一个错误:Error Code: 1363. There is no OLD row in on INSERT trigger
尽管有错误,但仍遵循逻辑...
如果旧代码不是一个子集,则通过调用存储过程自动删除它们。
DELIMITER $$
CREATE PROCEDURE delete_code(
in_id INT,
old_code varchar(6)
)
BEGIN
DELETE FROM code_detail WHERE id = in_id AND code = old_code;
END$$
DELIMITER ;
它可以从只有一个旧代码到任意数量的代码,其中'id = 2'。在任何情况下,如果旧代码不是插入的新代码的子集,则必须删除旧代码。
触发器和存储过程不是我经常遇到的东西,但考虑到问题的性质以及应用程序其余部分的工作方式,我认为这是尝试这样做的原因。也许我错了任何建议将不胜感激。
附加问题:触发器是否遍历code_detail
表中的所有行,还是只检查进行插入的行?如果是后者,那么旧的记录将被忽略,方法将不起作用。
1条答案
按热度按时间fnx2tebb1#
要问自己的问题是:复制什么使
ON DUPLICATE KEY UPDATE
子句生效。在查询之前,您有一个值为(2,D)的PK。插入指定
VALUES ((2, 'D', 50), (2, 'E', 50))
。所以你的插入... ON DUPLICATE KEY UPDATE查找该记录,并为语句中的第一个元组更新该记录。
但是它插入第二个元组,因为那个元组不包含重复的键。它的关键字是2,E。它完全没有碰到你的2,C排。
在我看来,你需要更详细地制定你的商业规则。如果您使用UPDATE语句执行的业务操作实际上意味着“删除所有id=2的现有行并将其替换为这些行”,那么您不能使用MariaDB / MySQL数据库约束操作来实现这一点。您需要显式地执行删除然后插入操作。
如果行已经存在,您也许能够找到一种方法来避免删除它们,而只是更新它们。但我怀疑触发器是解决问题的方法。如果你能让它工作,它将是复杂的--复杂到足以让下一个处理你代码的人说你的坏话。
触发器仅检查正在插入、更新或删除的行。