WITH (...) IF ... IN ... in MySQL 触发器
WITH (...) IF ... IN ... in MySQL trigger
鉴于简单 table(我正在使用 MySQL 服务器 8.0.17)
CREATE TABLE folders (
id varchar(3) NOT NULL,
parent varchar(3) DEFAULT NULL,
PRIMARY KEY (id),
KEY fk_folders_parent_idx (parent),
CONSTRAINT fk_folders_parent FOREIGN KEY (parent) REFERENCES folders(id) ON DELETE RESTRICT ON UPDATE RESTRICT
);
我想防止循环引用。我通过创建一个更新触发器来尝试这个(因为在一个一个地插入项目时不可能创建循环依赖)。
触发代码如下(我自己定位here and here):
DELIMITER $$
CREATE TRIGGER `test`.`folders_BEFORE_UPDATE` BEFORE UPDATE ON `folders` FOR EACH ROW
BEGIN
WITH RECURSIVE children (id) AS
(
SELECT id FROM folders WHERE parent = NEW.id
UNION ALL
SELECT f.id FROM folders f INNER JOIN children ON f.parent = children.id
)
IF NEW.parent IN children THEN
signal sqlstate '45000' set message_text = 'My Error Message'
END IF
END$$
我收到非常有用的错误消息:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF NEW.parent IN children THEN signal sqlstate '45000' set message_text ' at line 9
我相信是因为我不能使用WITH children (...) IF NEW.parent IN children
我尝试了 WITH children (...) IF EXISTS (SELECT id FROM children WHERE id = NEW.parent)
,但得到了相同的响应。
MySQL Workbench 告诉我,第 4 行的 BEGIN 没有 END。但是我不认为这是这里的问题。
我的 MySQL 有点生疏和过时了,因为我的大部分任务现在都是在 MS SQL 上完成的,但是试试这样的事情:
DECLARE found INT;
WITH RECURSIVE children (id) AS
(
SELECT id FROM folders WHERE parent = NEW.id
UNION ALL
SELECT f.id FROM folders f INNER JOIN children ON f.parent = children.id
)
SELECT id INTO found
FROM children
WHERE id = NEW.parent
LIMIT 1
;
IF NEW.parent = found THEN
signal sqlstate '45000' set message_text = 'My Error Message'
END IF
编辑(下面是Le 'nton
的最终解决方案):
DELIMITER $$
DROP TRIGGER IF EXISTS `test`.`folders_BEFORE_UPDATE`$$
CREATE TRIGGER `test`.`folders_BEFORE_UPDATE` BEFORE UPDATE ON `folders` FOR EACH ROW
BEGIN
DECLARE result varchar(3);
WITH RECURSIVE children (id) AS
(
SELECT id FROM folders WHERE parent = NEW.id
UNION ALL
SELECT f.id FROM folders f INNER JOIN children ON f.parent = children.id
) SELECT id INTO result FROM children WHERE id = NEW.parent LIMIT 1;
IF NEW.parent = result then
signal sqlstate '45000' set message_text = 'Circular dependency detected!';
END IF;
END$$
鉴于简单 table(我正在使用 MySQL 服务器 8.0.17)
CREATE TABLE folders (
id varchar(3) NOT NULL,
parent varchar(3) DEFAULT NULL,
PRIMARY KEY (id),
KEY fk_folders_parent_idx (parent),
CONSTRAINT fk_folders_parent FOREIGN KEY (parent) REFERENCES folders(id) ON DELETE RESTRICT ON UPDATE RESTRICT
);
我想防止循环引用。我通过创建一个更新触发器来尝试这个(因为在一个一个地插入项目时不可能创建循环依赖)。
触发代码如下(我自己定位here and here):
DELIMITER $$
CREATE TRIGGER `test`.`folders_BEFORE_UPDATE` BEFORE UPDATE ON `folders` FOR EACH ROW
BEGIN
WITH RECURSIVE children (id) AS
(
SELECT id FROM folders WHERE parent = NEW.id
UNION ALL
SELECT f.id FROM folders f INNER JOIN children ON f.parent = children.id
)
IF NEW.parent IN children THEN
signal sqlstate '45000' set message_text = 'My Error Message'
END IF
END$$
我收到非常有用的错误消息:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF NEW.parent IN children THEN signal sqlstate '45000' set message_text ' at line 9
我相信是因为我不能使用WITH children (...) IF NEW.parent IN children
我尝试了 WITH children (...) IF EXISTS (SELECT id FROM children WHERE id = NEW.parent)
,但得到了相同的响应。
MySQL Workbench 告诉我,第 4 行的 BEGIN 没有 END。但是我不认为这是这里的问题。
我的 MySQL 有点生疏和过时了,因为我的大部分任务现在都是在 MS SQL 上完成的,但是试试这样的事情:
DECLARE found INT;
WITH RECURSIVE children (id) AS
(
SELECT id FROM folders WHERE parent = NEW.id
UNION ALL
SELECT f.id FROM folders f INNER JOIN children ON f.parent = children.id
)
SELECT id INTO found
FROM children
WHERE id = NEW.parent
LIMIT 1
;
IF NEW.parent = found THEN
signal sqlstate '45000' set message_text = 'My Error Message'
END IF
编辑(下面是Le 'nton
的最终解决方案):
DELIMITER $$
DROP TRIGGER IF EXISTS `test`.`folders_BEFORE_UPDATE`$$
CREATE TRIGGER `test`.`folders_BEFORE_UPDATE` BEFORE UPDATE ON `folders` FOR EACH ROW
BEGIN
DECLARE result varchar(3);
WITH RECURSIVE children (id) AS
(
SELECT id FROM folders WHERE parent = NEW.id
UNION ALL
SELECT f.id FROM folders f INNER JOIN children ON f.parent = children.id
) SELECT id INTO result FROM children WHERE id = NEW.parent LIMIT 1;
IF NEW.parent = result then
signal sqlstate '45000' set message_text = 'Circular dependency detected!';
END IF;
END$$