MySQL:自定义行验证

时间:2013-06-01 20:15:26

标签: mysql foreign-keys

我有这样的例子:

CREATE TABLE a(
    id INT PRIMARY KEY AUTO_INCREMENT,
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES a(id)
);

DELIMITER ;;

CREATE TRIGGER a_insert BEFORE INSERT ON a
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '01431' SET MESSAGE_TEXT = 'The foreign data source you are trying to reference does not exist.';
END;;

DELIMITER ;


INSERT INTO a(parent_id) VALUES (NULL);
INSERT INTO a(parent_id) VALUES (1);
INSERT INTO a(parent_id) VALUES (2);
INSERT INTO a(parent_id) VALUES (4);
INSERT INTO a(parent_id) VALUES (999);

SELECT * FROM a

这最终有4个recods:

----------------
id     parent_id
----------------
1      NULL
2      1
3      2
4      4

我发现在线发帖称MySQL不支持触发器中的回滚。这是一个问题,因为我想要这样的层次结构,其中没有行指向它自己和像ID=4那样插入的工作正常。如何确保数据库中没有此类记录?

1 个答案:

答案 0 :(得分:1)

嗯,问题在于auto_increment,因为您在BEFORE INSERT事件中尚未分配该值。另一方面,在AFTER INSERT事件中你无法做任何事情。

如果您想使用auto_increment id列,可能的解决方案是使用单独的表进行排序。

您的架构看起来像

CREATE TABLE a_seq(
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE a(
  id INT NOT NULL PRIMARY KEY DEFAULT 0,
  parent_id INT,
  FOREIGN KEY (parent_id) REFERENCES a(id)
);

你的触发器

DELIMITER $$
CREATE TRIGGER a_insert 
BEFORE INSERT ON a
FOR EACH ROW
BEGIN
  INSERT INTO a_seq VALUES(NULL);
  SET NEW.id = LAST_INSERT_ID();
  IF NEW.id = NEW.parent_id THEN
    SET NEW.id = NULL;
  END IF;
END$$
DELIMITER ;

如果id=parent_id触发器故意违反NOT NULL约束,则指定NULL值。因此,不会插入此记录。

这是 SQLFiddle 演示。取消注释上一个插入语句。它不允许你制作这样的插页。