MySQL - 防止一行引用自己

时间:2015-08-19 18:58:30

标签: mysql sql ddl

我有一个表类别,结构如下:

----------------------------------
| id (PK) | name | parentId (FK) |
----------------------------------

其中 parentId 可以引用同一个表中的一行。

我想阻止更新某行,以便它引用自身( parentId != id )。我知道我必须使用数据库触发器,但我不知道它应该如何。我该怎么办呢?

我知道我可以(并且也会)在应用程序逻辑中处理这个问题,但我不认为这只是在应用程序逻辑中处理这些事情的好习惯。

我还想阻止插入和更新的循环引用,但我想这是一个不同的问题。

2 个答案:

答案 0 :(得分:3)

使用检查约束会更容易:

ALTER TABLE categories 
ADD CONSTRAINT categories_no_self_ref_ck CHECK (id != parentid)

答案 1 :(得分:0)

经过大量谷歌搜索,思考和阅读教程后,我设法创建了我想要的触发器:

DELIMITER $$
CREATE TRIGGER prevent_circular_reference
    BEFORE UPDATE ON category
    FOR EACH ROW BEGIN
        DECLARE x INT;
        SET x = NEW.parentId;
        WHILE x > 0 DO
            IF OLD.id = x THEN
                SIGNAL SQLSTATE "45000"
                    SET MESSAGE_TEXT = "Cannot change parentId as it would create a circular reference.";
            END IF;
            SELECT parentId FROM category WHERE id = x INTO x;
        END WHILE;
    END;$$
DELIMITER ;

在每次更新表之前触发触发器。它检查应该成为当前类别的父类别的类别不是当前类别的子类。如果通过更新创建循环引用(包括引用自身的行),则使用SIGNAL关键字引发错误。

请注意,这会将 id 设置为从1开始的自动增量(默认行为),因为如果SELECT返回NULL,则会将<0>插入 x