问题
I have a table called BFFs, that stores userID, and best friend's userID and I would like to restrict that table to have exactly 3 number of best friends for each different user.
I mean if the table structre is:
BFFs(userID, userID)
and records are:
(3286, 1212)
(3286, 4545)
(3286, 7878)
And in that case, if user with ID 3286 should not be allowed to have a new record such as (3286, xyzt).
I wrote this trigger but I'm not sure:
CREATE TRIGGER BFFControl
BEFORE INSERT ON BFFs
FOR EACH ROW
DECLARE
numberOfBFFs INTEGER;
max_BFFs INTEGER := 3;
BEGIN
SELECT COUNT(*) INTO numberOfBFFs
FROM BFFs
WHERE sender =: NEW.sender
IF :OLD.sender =: NEW.sender THEN
RETURN;
ELSE
IF numberOfBFFs >= max_BFFs THEN
RAISE_APPLICATION_ERROR(-20000, 'Users are allowed to have at most thre friends.');
END IF;
END IF;
END;
/
How should I restrich this on relational tables through assertions or triggers ?
Thanks
回答1:
Add another column, FriendNumber and a Foreign Key constraint to a reference table with exactly 3 rows:
CREATE TABLE Three
( friendNumber TINYINT NOT NULL
, PRIMARY KEY (friendNumber)
) ;
INSERT INTO Three(friendNumber)
VALUES
(1), (2), (3) ;
CREATE TABLE BFFs
( userID INT NOT NULL
, friendID INT NOT NULL
, friendNumber TINYINT NOT NULL
, PRIMARY KEY (userID, friendID)
, UNIQUE (userID, friendNumber)
, FOREIGN KEY userID
REFERENCES Person(userID)
, FOREIGN KEY friendID
REFERENCES Person(userID)
, FOREIGN KEY friendNumber --- this ensures that a user can have
REFERENCES Three(friendNumber) --- max of 3 friends
) ;
Then you can add:
INSERT INTO BFFs
(userID, friendID, friendNumber)
VALUES
(3286, 1212, 1) ,
(3286, 4545, 2) ,
(3286, 7878, 3) ;
or as suggested by @gbn, to something like this (so the column is auto-filled):
INSERT INTO BFFs
(userID, friendID, friendNumber)
SELECT
3286 AS userID
, 8989 AS friendID
, COALESCE(
( SELECT MIN(Three.friendNumber)
FROM Three
LEFT JOIN BFFs AS b
ON b.friendNumber = Three.friendNumber
AND b.userID = 3286
WHERE b.friendNumber IS NULL
), 4
) AS friendNumber
FROM dual
回答2:
In addition to ypercubes' answer (whcih leverages DRI to enforce your rule), you can also LEFT JOIN with MIN to get the next of 1, 2 or 3 from the Three table per userID
来源:https://stackoverflow.com/questions/9621509/limit-number-of-records-using-trigger-and-constraints-in-mysql