简体   繁体   中英

Users and Groups: 3 or 2 tables (SQL)

I'm wondering about the pros and cons of storing my users and their groups in 3 tables vs. 2 tables.

Pros of 2 tables

  1. The groups could easily just be users themselves and would seem in most scenarios to share all the same fields as users, ie, name, picture, password, email.

Pros of 3 tables

  1. Having a 3rd groups table would be more explicit so this might be easier for developers to understand/maintain.

Cons of 3 tables 1. Violating DRY principles across application code by not doing the #1 in the "Pros of 2 tables" above.

What else should I be thinking of?

The 2 mandatory tables are a users table and a group_member table.

+---------+      +------------+
| users    |      | group_member |     +----------+
+---------+      +------------+     | groups    |
| user_id |----->| user_id    |     +----------+
| name    |      | group_id   |<----| group_id |
| pass    |      +------------+     | name     | 
| ...     |                         | ...      |
+---------+                         +----------+

                                    **theoretical 3rd table**

note: The user_id and the group_id in the group_member table would both be referring to the user_id in the users table

Main point: if you want to store users & groups in one table as they share (most) characteristics, this is perfectly valid. However , this would mean that technically a group can be a member of a user, and you can't enforce on a database level that users can be in groups and not the other wary around:

Scenario in 1 table:

CREATE TABLE users_and_groups (id int...
CREATE TABLE group_members (
    group_id, 
    user_id
    FOREIGN KEY (group_id) REFERENCES users_and_group (id) -- no way to limit on only groups
    FOREIGN KEY (user_id) REFERENCES users_and_group (id) -- no way to limit on only users   
)

Scenario in 2 tables:

CREATE TABLE users (id int...
CREATE TABLE groups (id int...
CREATE TABLE group_members (
    group_id, 
    user_id
    FOREIGN KEY (group_id) REFERENCES groups (id) -- guarantees a group
    FOREIGN KEY (user_id) REFERENCES users (id)   -- guarantees a user
)

Setting up a database defensively like this can prevent a whole lot of hurt if bugs at the application level arise.


If however, the user & group entities share a lot of data (can both own other objects for instance, have profile pages, etc.), a 4 table solution can work out well:

CREATE TABLE users_and_groups (id, ...shared data...
CREATE TABLE users (users_and_groups_id, ...user specific data...
CREATE TABLE groups (users_and_groups_id, .. group specific data...
CREATE TABLE group_members (
    group_id, 
    user_id
    FOREIGN KEY (group_id) REFERENCES groups (users_and_groups_id) -- guarantees a group
    FOREIGN KEY (user_id) REFERENCES users (users_and_groups_id)   -- guarantees a user
)

This has several advantages:

  • foreign keys where either groups or users are allowd can be in 1 column.
  • at the application level, this is classic inheritance: a base users_and_groups , and both user & group extend that base class/table.
  • enforcing either a group or a user is still possible with foreign keys
  • if users or groups get specific data, there is no need to add a column to a table which is useless for a large portion of the records, it can be stored in the type-specific tables.

Some disadvantages:

  • it is impossible to enforce that an entity is either a user or a group, but not both or none (type-less)
  • unless you store a redundant column type (or is_group / is_user ), determining whether an entity is a group or a user requires a JOIN , but as this is on primary key on both sides, the overhead should be small

If anything, I think group_member would be the optional table. You'd only want this table if you needed a many-to-many relationship between users and groups . In other words, if a user can belong to more than one group, you'd want a table that can link a user_id to a group_id . If a user can only belong to one group, you'd probably still want a groups table, and then have a group_id column on the users table.

But, to answer your original question, if you stored the group information (such as the group name) in the group_member table, you'd have to repeat this data for each user within the group. You'd have many rows that have the same group name, and if you wanted to then change a group name later, you'd have to update many rows rather than just one. It also makes it very difficult to tell who's in the same group, and a lot of those sorts of queries would become very inefficient.

Normalizing your distinct groups into a single groups table is definitely the right approach, regardless of whether you use one or two tables.

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