MySQL - 防止一行引用自身
MySQL - prevent a row from referencing itself
我有一个 table 类别 具有以下结构:
----------------------------------
| id (PK) | name | parentId (FK) |
----------------------------------
其中 parentId 可以引用同一个 table 中的一行。
我想防止更新一行以使其引用自身 (parentId != id)。我知道我必须使用数据库触发器,但我不知道它应该是什么样子。请问我该怎么做?
我知道我可以(也将)在应用程序逻辑中处理这个问题,但我认为仅在应用程序逻辑中处理这类事情不是一个好的做法。
我也想防止插入和更新时的循环引用,但我想那是另一个问题。
使用检查约束会更容易:
ALTER TABLE categories
ADD CONSTRAINT categories_no_self_ref_ck CHECK (id != parentid)
经过大量谷歌搜索、思考和阅读教程后,我成功地创建了我想要的触发器:
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 ;
触发器在 table 上的每次更新之前触发。它检查应该成为当前类别的父类别的类别不是当前类别的子类别。如果通过更新创建循环引用(包括引用自身的行),则使用 SIGNAL 关键字会引发错误。
请注意,这假设 id 设置为从 1 开始自动递增(默认行为),因为如果 SELECT returns NULL,a零被插入 x.
我有一个 table 类别 具有以下结构:
----------------------------------
| id (PK) | name | parentId (FK) |
----------------------------------
其中 parentId 可以引用同一个 table 中的一行。
我想防止更新一行以使其引用自身 (parentId != id)。我知道我必须使用数据库触发器,但我不知道它应该是什么样子。请问我该怎么做?
我知道我可以(也将)在应用程序逻辑中处理这个问题,但我认为仅在应用程序逻辑中处理这类事情不是一个好的做法。
我也想防止插入和更新时的循环引用,但我想那是另一个问题。
使用检查约束会更容易:
ALTER TABLE categories
ADD CONSTRAINT categories_no_self_ref_ck CHECK (id != parentid)
经过大量谷歌搜索、思考和阅读教程后,我成功地创建了我想要的触发器:
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 ;
触发器在 table 上的每次更新之前触发。它检查应该成为当前类别的父类别的类别不是当前类别的子类别。如果通过更新创建循环引用(包括引用自身的行),则使用 SIGNAL 关键字会引发错误。
请注意,这假设 id 设置为从 1 开始自动递增(默认行为),因为如果 SELECT returns NULL,a零被插入 x.