简体   繁体   中英

Many-to-One and One-to-One Relationships on Same Two Tables?

I'm designing a database where two fields have a many-to-one relationship, but I also need a one-to-one relationship between them, and I would like some advice on whether there is a better way to do it than what I've got right now.

My tables are accounts and users . An account can have multiple users, but each account can only and must have one owner. A user can be related to only one account.

I have an account field in the users table, which stores the ID of the account the user is related to. In the accounts table, I have an owner field, which stores the ID of the user who owns the account (ie the head admin).

I'm using InnoDB so I can make use of foreign keys. The problem is that I can't create an account or a user without the other being created first (due to the restraints of the foreign keys), so I made owner nullable. Now I can create an account with a null owner , then create the user, and finally set the owner on the account to the user.

Is this acceptable, and is there a better way?

Here are some possible other ways I've come up with, and my thoughts on each:

  1. Have a boolean owner field in the users table. Since every account can only have one owner, this way seems less than ideal because I'd have to ensure only one user per account has the attribute set to true .

  2. Have a third table called owners . This seems like more overhead and more work for no good reason since it's effectively the same as having an owner field in the users table.

How I have it now makes the most sense to me, but it's a little awkward having to set a null owner until I create the user, and then coming back to set it after the fact.

I'd appreciate any input you can give me. Thanks!

This question is similar, but there's no mention of foreign keys: Designing Tables: One to many and one to one at same time?

In general is a bad idea if your schema cannot be sorted topologically, ie if you cannot establish an ordering where a table only refers to tables preceding it in the ordering. This sort of "layered" dependency is also a very nice property to have for example for software modules (you have a problem if two modules depends on each other).

In your case you have user that refers to account and account that refers to user so clearly there's no way to find a topological ordering.

One standard solution in this case is to introduce a separate table eg "role" where you have three columns: user, account and role. The column role can be either "owner" or "guest".

The fact that you know that (given the current requests) an account must have one and only one owner, or that a user must be listed in one and only one account are not IMO rules that are really pertinent to the domain of "users" and "accounts".

You can implement those rules easily, but structuring your data so that you have no other possibility is IMO a mistake. You should aim to model the domain, not the specific rules... because people will change their mind about what those rules are.

Can you conceive a user with two accounts? Can you conceive an account with multiple owners/admins? I can... and this means that most probably quite soon this will be a request. Structuring the data so that you cannot represent this is looking for troubles.

Also when you have cyclical dependencies in the model your queries will be harder to write.

A very common case is for example to try to represent a hierarchical part list database using just one table with a "parent" field that points to the table itself... much better is having two tables instead, part and component, where component has two references to part and and a quantity.

Your solution is fine.

If you're uncomfortable with the owner column being nullable, you could rely on some magic user record (perhaps with an id of zero) which would be the "system user". So newly created accounts would be owned by user-zero, until their ownership was suitably redefined. That seems smellier than allowing accounts to have a null owner, to me, anyway.

在此处输入图像描述

For the current requirement to have only one account per user

alter table UserAccount add constraint un_user_account unique(UserID);

and when the requirement changes to many-to-many, drop the constraint

alter table UserAccount drop constraint un_user_account;

For the one owner only, simply enforce that on the application level.

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