Im thinking about what is the better way to design a database with the following statements:
There are 3 kinds of users (3 differents roles).
They have some common fields, however they have differents fields too.
Solution A:
All user in the same table (some users will have empty fieds depending of their role).
Solution B:
A main table where i will add users and their role. In addition i will create 3 extra tables where i will record with extra fields (depending of the table) and each record will have an id related with the user in the main table.
Solution C: A main table with basic user info, and a second table with the metadata user info where each record means a field of a user. That it's similar than WordPress
Yours is a case of Specialization/Generalization. Since you said User (1, 2, 3) share common properties, it is best to have a General entity - User with all the common attributes.
Then you can Specialize to 3 different types and have the specific attributes to each type.
So, option B is what I think is best solution for your problem.
Option A will cause too many null values and option C is overly complicated.
That depends :-)
Will you ever treat the users the same? E.g. at login time: Will someone just login with a username and this can be any of the three user types? Then you need a user table with a username and a unique index on it. This is solution A or B. I'd prefer B over A, so you can decide which of the fields are nullable for the specific role.
Or will you never deal with a user with an unknown role (such as: a person logs in with a role plus a username, so it suffices to have three different tables each with their own usernames)? This would be three special user tables and no common user table.
Option C would be something easy to implement in order to give users additional attributes, but can become a hassle. Especially when there are obligatory fields and fields that link to other tables (such as a job number that is meant to be the key in the jobs table, but you cannot use a foreign key then). I usually don't take this route, if it is avoidable.
Related
I have a requirement to show Different fields to Different User Types.
For Example, Admin UserType, show the form with 10 attributes
Super UserType, show the form with 2 attributes
Normal UserType, show the form with 2 attributes
How do I design the database table such a way UserType and the attributes are dynamic ?
Raja K
I imagine there are some common attributes among the users, right? You might approach this by "supertyping" the tables. First create a base table with the common attributes. Something like this:
Users
----------
ID (PK)
Username
AccountCreatedDate
etc.
Any user account would have a record in this table. Depending on whether or not it makes ongoing operations simpler you might even include a flag in the table indicating the user type.
You might then add additional tables for the other user types, where their PK is also a FK to this base table. Something like this:
AdminUsers
----------
ID (PK, FK to Users)
etc.
That would contain the attributes specific to an admin user. Another table would contain attributes specific to a super user. And so on. An added benefit here is that a single user can have multiple roles and be interpreted in multiple ways depending on the use case. And you can have some simple compiled views in the database which make querying the table structure easier.
This would work well for a static set of user types. If that set is going to change often during normal application usage (that is, if one of the operations of the application is that people can add user types) then you wouldn't want a rigid schema.
In cases like that you might make treat the fields as meta-attributes on a generic table of user properties. So you might have your base table again:
Users
----------
ID (PK)
Username
UserType
etc.
And then you might have a generic table of properties:
UserProperties
----------
ID (PK)
UserID (FK to Users)
PropertyName
PropertyValue
This is more dynamic, but it has some drawbacks that come to mind:
You can't maintain data types in the database. Everything becomes "stringly typed" and it's up to the application to interpret the types correctly. This will result in a ton of defensive programming code in the application.
You can't maintain the schema in the database. Things like required properties would need to be maintained by the application, the database couldn't guarantee it. So the potential for dirtier data is higher.
It's more difficult to query and report on this structure.
So there are pros and cons either way, whichever approach you take is up to you and the needs of the system you're building.
I have a users table in my database and have three kinds of user roles - manager(admin), expert, and student.
I have tried storing their role as column role in the users table, but my question is what is the best way to store it?
For example, should I use numbers - 1 for admin, 2 for expert and 3 for student. Or only one character - 'A' for admin , 'E' for expert and 'S' for student? Or full string 'admin' for admin and so on, or what?
Edit
Guys, I want most efficient way. Some of you told me to have another table but this relationship isn't many to many, it's one to many because users can only have one role.
You might want to have a separate junction table, eg user_roles that will have columns: id, user_id and role_id. This way each user can have multiple roles in the future, even if right now they only have 1.
And that role_id would point to a role in a new roles table, which could have all the data associated with the roles.
Or if you really don't want the junction table, then just put the role_id directly into your users table.
Look up database "normalization". Basically if you have a specific set of data that will be repeating in a column, you might want to put it in its own table.
You could create a separate table showing 2 columns: role_nbr, role with values like:
1, Admin;
2, Expert;
3, Student
Then include role_nbr in your users table and use numbers, linking it to the role table to lookup the role name. That way, if you ever increase your roles, it's easy to add to the separate table. A good study would be on normalization - this will help you eliminate storing duplicate information where you have a lot of information to store (like the role name - since storing a number or letter - how would you remember what it stood for?)
Use the enum type. Here is an example
CREATE TABLE users (
-- the other columns
role ENUM('admin, 'expert', 'student')
);
An ENUM is a string object with a value chosen from a list of permitted values that are enumerated explicitly in the column specification at table creation time.
This means that the enum type has already defined values (and can contain only one value per row - you can't have a user who is admin and at the same time student). In your case, they are admin, expert and student.
DOCS
I am designing a database for MySQL to create a relationship between two users of an application. I am unsure of the best way to store the particulars of this relationship, though I currently intend to use one record per relationship in a link table called RELATIONS. Each user has basic data like their name and occupation stored in the USERS table, and more specific personal data stored linked by FKs in other tables, which we'll say are called OTHER1, OTHER2, and OTHER3, which will all contain some other data to be shared, we'll say each in a field called [Data] and identified with ID and USER_ID.
The difficulty is that the application allows users to specify what basic and advanced data that they show to each user, and vice versa. The RELATIONS link table needs to have FKs to USERS for the two users to set up the relationship, but I don't know how best to specify what data each user is able to share, because virtually all of the data that the database stores is stored optionally but all needs to possibly be hidden from a user that doesn't have permission to view it. The second user should be able to see if there is data there, however, so that he might request permission to view it.
My model for RELATIONS at this point looks like this:
RELATIONS
ID
USER_ID1
USER_ID2
USER1OTHER1_ID [(Value), Unshared, Null]
...
USER1OTHER100_ID [(Value), Unshared, Null]
USER2OTHER1_ID [(Value), Unshared, Null]
...
USER2OTHER100_ID [(Value), Unshared, Null]
So USER1OTHER1_ID will contain the FK to OTHER1 if User1 has shared it with User2, will be "Unshared" if it's present but unshared, and Null if User1 has no data in OTHER1. Same for USER2OTHER1 for sharing with User1. I don't like having a massive field array, though, and I don't like how I'd have to update all the relations if User1 later decides to add data to OTHER1. Is there a simpler and more normalised way of representing this?
I believe the normalized approach would be to only store whether userA has permissions to view the userB's data and not add FK references to it in the Relations table because you already have references to userB's data somewhere else. By storing additional references in the Relations table you are duplicating data and will have to ensure that it stays synchronized as you described in your question which will probably be an ongoing maintenance hassle and one more thing you have to keep in mind whenever you refactor your code.
If you only store permissions (no fks) in the Relations table you would join on a table (User?) to get the User's shared data or to see if it exists depending on the permission.
As far as having an excessive number of columns on the relations table, I don't think you will have enough to see a real degradation when querying the table (you could correct me on this). For clarity sake in the db code as well as your application code, I think you are better off to have a column for each permission than to try to find a short cut such as combining them in a clob or something.
The most succinct way I can readily imagine is to store one INT with the relationship, which is a bit-wise representation of the permissions; with the interpretation of that INT in the code. The INT will need as many bits as you have unique permissions, and then define constants for each of them. I'm not sure what language you are implementing in, but there about a few ways to skin this cat...
So, some pseudo-code might look like this:
define RELATION_PERMISSION_SEE_MY_PHOTOS = 1;
define RELATION_PERMISSION_SEE_MY_FRIENDS = 1<<1;
define RELATION_PERMISSION_SEE_MY_EMAIL = 1<<2;
and then build some arrays of supporting info (like localized strings, etc) to build your interface with, and then do something like this to modify it:
int new_permission = 0
foreach(user-selected-permissions as selected_permission) {
new_permission |= selected_permission
}
my_relation_model.permissions_flags = new_permission
one way would be to use essentially key value pairs..
similar to this:
user_1_id
user_2_id
field
privilege
.. because virtually all of the data that the database stores is stored optionally ...
Considering this, I would suggest 6NF for all user attributes.
The User table serves as an anchor and ideally holds only UserID.
Each user attribute has its own table with only UserID and the attribute value (6NF); a row exists only if the attribute is specified (all attribute values are NOT NULL).
Each attribute has also a sharing table with only OwnerID, VisitorID. A row exists only if the owner shares the attribute with the visitor.
In this model, a user can share only attributes that do exists. If you want to allow sharing of not specified attributes, point the OwnerID to the User table too.
To make thing simpler you can (should) create a view(s) for user data.
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 (i.e. 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:
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.
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, i.e. 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 e.g. "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.
I'm building an application that will have two different types of users, lets call one User_type_a and the other User_type_b. I'm wondering if I should create 1 table in my database for both types of users and have a property distinguishing what type of user each record is, or if I should create two separate tables for each type of user.
Considerations:
1. 99% of all users will be User_type_a
2. User_type_b will require properties in addition to User_type_a (such as credit card #'s, etc)
Which design approach is optimal? Or does it not really matter.
One table for users, assuming that user type b are real users. Create another table that links to the user table to store the CC details for user type B.
This allows you do do all major user changes easily (searching users, changing user details, looking up users for login, etc), but doesn't contain many wasted columns.
Note that if you are storing credit card numbers, your datacenter and architecture will have to be PCI compliant, which is expensive.
If type B has only additional information (columns) to the generic user type then use:
If types A and B have some common columns and a set of distinct columns for each one, then use
I both cases keep all common columns in the User table -- sub-type tables have only columns specific to each one. Note that UserID propagates to sub-type tables.
The best way to do this would be to store all users in the same table, and have a foreign key relating to a second table, which contains the extra information.
**USER TABLE**
NAME AGE TYPE FK
Grant 25 Adult 1
Susan 4 Child null
John 65 Adult 2
**EXTRA TABLE**
FK CREDITCARD OTHER
1 234234... blah
2 2334... blah
This would be more efficient with space.
So it sounds like User_type_a and User_type_b are both identical in terms of data, with the exception being that User_type_b has additional data above and beyond User_type_a (but User_type_a does not have any unique data like this).
Given this, I would create a single users table that stores the User_type_a data (i.e. the intersection of the two user types). Then create a second table for the additional User_type_b data, with a foreign key linking that one back to users. (Note that there is no column here in the users table defining which users are which type.)
How to tell the difference between the two user types? Simple: User_type_b has a related row in the second table; User_type_a does not. This makes it easy for any application functions that don't care about the difference to just get the common user data for everyone, while functions that need the extra User_type_b data (or otherwise only care about one type or the other) can still determine who is what type and get that extra data.
Use one table. They are both users. Your code will have more general use between both types so you will avoid having to do 2 sql queries when dealing with users (even though they are not relevant 99% of the time)