Mysql:关联表

时间:2014-12-11 10:52:22

标签: mysql model-associations

使用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

它有效,但是有更好的方法吗?

1 个答案:

答案 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);
  • 详细了解信号here
  • here为什么我选择23000作为sqlstate(但事实上并不重要)