unique pair in a “friendship” database

房东的猫 提交于 2019-12-05 08:05:42

You're probably not going to be able to do this at the database level -- your application code is going to have to do this. If you make sure that your tbl_friends records always go in with (lowId, highId), then a typical PK/Unique Index will solve the duplicate problem. In fact, I'd go so far to rename the columns in your tbl_friends to (id_low, id_high) just to reinforce this.

Your query to find anything with user 713 would then be something like

SELECT id_low AS friend FROM tbl_friends WHERE (id_high = ?)
UNION ALL
SELECT id_high AS friend FROM tbl_friends WHERE (id_low = ?)

For efficiency, you'd probably want to index it forward and backward -- that is by (id_user, id_friend) and (id_friend, id_user).

If you must do this at a DB level, then a stored procedure to swap arguments to (low,high) before inserting would work.

You'd have to use a trigger to enforce that business rule.
Making the two columns in tbl_friends the primary key (unique constraint failing that) would only ensure there can't be duplicates of the same set: 1, 2 can only appear once but 2, 1 would be valid.

how would I seach for all of the friends of user 713 while he could be mentioned, on some friendship rows, at the second column ('id_friend')?

You could use an IN:

WHERE 713 IN (id_user, id_friend)

..or a UNION:

JOIN (SELECT id_user AS user
        FROM TBL_FRIENDS
      UNION ALL
      SELECT id_friend
        FROM TBL_FRIENDS) x ON x.user = u.user

Well, a unique constraint on the pair of columns will get you half way there. I think the easiest way to ensure you don't get the reversed version would be to add a constraint ensuring that id_user < id_friend. You will need to compensate for this ordering at insertion time, but it will get you the database Level constraint you desire without duplicating data or relying on foreign keys.

As for the second question, to find all friends for id=1 you could select id_user, id_friend from tbl_friend where id_user = 1 or id_friend = 1 and then in your client code throw out all the 1's regardless of column.

One way you could do it is to store the two friends on two rows:

CREATE TABLE FriendPairs (
  pair_id INT NOT NULL,
  friend_id INT NOT NULL,
  PRIMARY KEY (pair_id, friend_id)
);

INSERT INTO FriendPairs (pair_id, friend_id)
VALUES (1234, 317), (1234, 713);

See? It doesn't matter which order you insert them, because both friends go in the friend_id column. So you can enforce uniqueness easily.

You can also query easily for friends of 713:

SELECT f2.friend_id
FROM FriendPairs AS f1
JOIN FriendPairs AS f2 ON (f1.pair_id = f2.pair_id)
WHERE f1.friend_id = 713
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!