Mysql : Association table

五迷三道 提交于 2019-12-11 14:13:26

问题


Using mySQL, I have these tables:

Person
----------
id (PK)
name
...


Person_Association
----------
id_Person1  (FK Person.id)
id_Person2  (FK Person.id)

I want each Person_Association to be unique: if (#1, #2) exists, then neither (#1, #2) nor (#2, #1) can be inserted.

To do that I've added a field and a trigger to Person_Association, like this:

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

It works, but is there a better way to do that?


回答1:


You better throw away the trigger and have an unique index on (id_Person1, id_Person2).
Actually you can also throw away the unnecessary unique_id and make (id_Person1, id_Person2) the primary key.

Then you insert like this:

INSERT INTO your_table VALUES (LEAST($value1, $value2), GREATEST($value1, $value2));

or

INSERT INTO your_table SELECT LEAST($value1, $value2), GREATEST($value1, $value2);

EDIT: If you really insist on "SQL to assure that (not the application layer)", I'd write it like this (but still have your unique_id column removed and an unique index on (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 ;

I'd still prefer not to have a trigger on the table (that's from database administrators view, not only do they often cause confusion, but they tend also to get in the way when doing administrators tasks). So, to pursuit my first way of solving it, you can also create a stored procedure to do this for you:

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);

and in your application layer you just do

CALL insert_p_a($value1, $value2);
  • read more about signals here.
  • here's why I chose 23000 as sqlstate (but in fact it doesn't matter)


来源:https://stackoverflow.com/questions/27421087/mysql-association-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!