使用mySQL,我有这些表:
Person
----------
id (PK)
name
...
Person_Association
----------
id_Person1 (FK Person.id)
id_Person2 (FK Person.id)
我希望每个Person_Association都是唯一的:如果(#1,#2)存在,则不能插入(#1,#2)和(#2,#1)。
为此,我为Person_Association添加了一个字段和一个触发器,如下所示:
Person_Association
----------
id_Person1 (FK Person.id)
id_Person2 (FK Person.id)
unique_id (PK)
CREATE TRIGGER `Person_Association_BINS` BEFORE INSERT ON `Person_Association` FOR EACH ROW
BEGIN
IF (new.id_Person1 < new.id_Person2) THEN
SET new.unique_id = CONCAT(new.id_Person1, '-', new.id_Person2);
ELSE
SET new.unique_id = CONCAT(new.id_Person2, '-', new.id_Person1);
END IF;
END
它有效,但是有更好的方法吗?
答案 0 :(得分:1)
你最好扔掉触发器并在(id_Person1, id_Person2)
上有一个唯一索引
实际上,您也可以丢弃不必要的unique_id
并将(id_Person1, id_Person2)
作为主键。
然后你插入如下:
INSERT INTO your_table VALUES (LEAST($value1, $value2), GREATEST($value1, $value2));
或
INSERT INTO your_table SELECT LEAST($value1, $value2), GREATEST($value1, $value2);
编辑:如果你真的坚持“SQL来确保(不是应用程序层)”,我会这样写(但仍然删除了你的unique_id列和(id_Person1, id_Person2)
上的唯一索引):
DELIMITER $$
CREATE TRIGGER `Person_Association_BINS` BEFORE INSERT ON `Person_Association` FOR EACH ROW
BEGIN
IF EXISTS(SELECT 1 FROM `Person_Association` WHERE id_Person1 = LEAST(NEW.id_Person1, NEW.id_Person2) AND id_Person2 = GREATEST(NEW.id_Person1, NEW.id_Person2)) THEN
SIGNAL SQLSTATE '23000' SET MESSAGE_TEXT='dup key error';
END IF;
END $$
DELIMITER ;
我仍然不希望在桌面上有一个触发器(这是来自数据库管理员的视图,它们不仅常常引起混淆,而且在执行管理员任务时也会妨碍它)。因此,为了追求我的第一种解决方法,您还可以创建一个存储过程来为您执行此操作:
CREATE PROCEDURE insert_p_a(IN p_id1 INT, IN p_id2 INT)
INSERT INTO your_table SELECT LEAST(p_id1, p_id2), GREATEST(p_id1, p_id2);
并在您的应用程序层中执行
CALL insert_p_a($value1, $value2);