Reputation: 1870
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?
Upvotes: 0
Views: 3318
Reputation: 51888
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);
Upvotes: 1