【问题标题】:WITH (...) IF ... IN ... in MySQL triggerWITH (...) IF ... IN ... 在 MySQL 触发器中
【发布时间】:2019-08-01 22:55:07
【问题描述】:

给定简单的表(我使用的是 MySQL Server 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
);

我想防止循环引用。我通过创建更新触发器来尝试此操作(因为在逐个插入项目时无法创建循环依赖项)。

触发代码如下(我定位了自己herehere):

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 的 CTE,但它应该让你那样使用它们吗? MySQL 通常不允许您混合查询和过程语法。你可以做一个WITH...INSERT INTO tempTable ..... SELECT * FROM theWith 然后检查 tempTable 的内容。
  • @Uueerdo 谢谢!做到了!我会尽快发布我的解决方案!

标签: mysql mysql-8.0


【解决方案1】:

我的 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$$

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 2015-06-02
    • 2013-01-28
    • 2021-06-23
    • 2012-05-09
    相关资源
    最近更新 更多