MySQL的:关联表(Mysql : Association table)

2019-10-30 06:13发布

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

它的工作原理,但有一个更好的方式来做到这一点?

Answer 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);
  • 阅读更多关于信号在这里 。
  • 这里就是为什么我选择23000作为SQLSTATE(但实际上它并不重要)


文章来源: Mysql : Association table