简体   繁体   中英

Many-to-many on same table

Funny that I've never come across this yet!

It never occurred to me that one could have a "many to many" relationship on one table- until I started working on a system where users can "friend" each other (social networking).

A standard lookup table, at least in the way that I'm used to using it, isn't appropriate here. Lets keep it simple:

User table has "id" and "name" column.

User_relationship table has "uid1" and "uid2", representing users that are "friends" or "buds" or "pals" or "whatever else".

It becomes apparent pretty quick what the problem here is- uid1 and uid2 are the same data type from the same column of the same table, meaning that unique keys become flawed.

Eg: uid1 = 1 uid2 = 2

Is the same as:

uid1 = 2 uid2 = 1

And therefore could return 2 records, or 0 records if the query is performed wrong.

In the spirit of designing a table well, I don't want to have to scan the entire table twice to check for existing values.

Is there some sort of trick for handling this? This is a design question that has never occurred to me, and it irks me because I know that there's some simple trick to make it work.

Before you ask, I haven't tried anything yet, because I already see that my favorite way of relating things (lookup tables) is insufficient for my needs here, and I need some help- I can't find anything on SO or Google :(

Thanks in advance.

If the relationship you're describing is symmetrical, as in "Bob is a friend of Joe" means "Joe is also a friend of Bob", then you can make sure in your code that the smaller of the 2 user IDs goes on the first column, and the larger one goes on the second column. This constraint pretty much ensures that the records in your lookup table will be unique. It also means that when you're performing a lookup, you usually have to search both columns.

For example, if you were trying to get all of Bob's friends, you would have to query for records that have Bob's ID in either column. This leads to a bit more code and possibly an impact on performance.

If the relationship can be asymmetrical, as in "Bob is a friend of Joe" does not necessarily mean "Joe is also a friend of Bob", then you need 2 entries for every pair of users: Bob - Joe and Joe - Bob. This means that your lookup table will contain twice as many entries and also that your site is very stalker-friendly :D Of course, you can still choose to apply this system even though your relationship is symmetrical.

Using this method, if you want to get all of Bob's friends you just have to select the records with Bob's ID in the first column. It is possible that this might mean faster lookups and less code for you to write, but again, it means you're taking up more room in your database.

meaning that unique keys become flawed.

 uid1 = 1 uid2 = 2 

Is the same as:

 uid1 = 2 uid2 = 1 

Nope, it's not.

On Facebook, for instance, I've a number of customers who sent requests to become "friends" that I never accepted... Since they're mere acquaintances.

Along the same lines, I might have marked a few people as best friends, and they didn't reciprocate, or vice versa. Or perhaps I'm ignoring a few and they are not.

Basically, there's a lot more information in a (uid1, uid2) tuple than mere IDs.

Make sure that you never need to deal with situations like these before deciding to add eg a uid1 < uid2 constraint on your table.

This is not that uncommon.

Typically what is done is that there is a table, as in most many-many relationships that consists of two columns, each being an id, of the two tables, that make up the primary key.

As you stated userId1 and userId2. Attributes, if necessary, can be added to the relationship (such as classification of friendship).

When user 1 befriends user 2, there are typically two inserts, (1,2) and (2,1).

Same sort of thing with a defriending, there needs to be two deletes.

You could end up with a user having himself as a friend, and that might be critical to the actual workings of the system. If a user can only view photos of his friends, then if he is not a friend to himself, some systems might not allow him to see his own photos.

It is very dependent upon how the application is written on top of the database.

I agree with what others have said, it's isn't a bad idea to have 2 inserts for a relationship (1:2 and 2:1). This actually helps to expand some of the features which are commonly found in modern social networks. Some cases of practical use that I can think of is description of relationship or other attributes. While individuals remain friends they maintain different setting towards each other. In 1:2 relationship Bob is following Joe's updates and has him on best friend list (add bff column), while in 2:1 Joe doesn't have Bob on bff list and doesn't care to follow his posts (following column).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM