User, customer, admin account in 3 different tables? - database

In my web application I will have three types of accounts.
User: for using the web application for free
Customer: for advertising and getting a Company Logo
Admin: for editing and deleting stuff
Should all these three be in separate tables or in one with a column named "account_type" where i can mark it as User, Customer or Admin?
What are the pros and cons for both? Is there a best practice for this?
Thanks

In general, a person can be user, customer and admin -- so, I would start with a Person table with columns IsCustomer, IsUser, IsAdmin. Later (for fast search) you may decide to add separate tables Admin, Customers, Users with FK to the Person table.
EDIT:
A typical case may be:
5 million users
1000 customers
10 admins
In general, having separate tables for customers and admins should speed-up any admin/customer related query.

If a user can only be one type, you'd be better off with one table and a bit field for IsAdministrator, etc.
If a user can be of more than one account type, you should then have a different table with a foreign key,
sample structure (data sypes are SQL Server and suggested only)
Users table
UserID - int
Username - varchar(25)
Password - varchar(25)
Firstname - varchar(50) etc...
Roles table
RoleId - int
Role Description - varchar(25)
User_Roles table
UserId - int (with a foregin key to the Users table)
RoleId int (foreign key to the Roles table)

Pros and Cons vary based on the size and complexity of your system.
I would break it up into User, Role, UserResources
User (would define basic information)
User Roles
FK->RoleType
Role_Type (user, admin, customer, possibly permissions or you could break this out further).
UserResources (media)
FK->User

Related

Database schema for profile and order

I am working on a bank application in which a customer can open multiple accounts for different product types like: Insurance, Investment and annuity etc.
Each customer has a profile and we are saving that information in 12 different tables such as : Personal,Contact,Address,Affiliation,Financial,Investment,Asset,Liability,NetWorth and so on.
Now to open each account we have to collect and save same kind of information like for customer profile but we cannot overwrite the customer profile with that as we have to keep track of each accounts information when its submitted to the point when it get opened.
So in terms of solution we think either to have replica of these 12 tables for each account or to save the JSON for each table in one table only which has 12 columns for each of above table and populate UI with that.
Can somebody if have prior experience suggest us how to do this in best way.
I would determine which information will not change between accounts. For example, name, birthday, ssn, etc. These constant fields can form a table called customers. If there are no constant fields, then you can use a placeholder id, which simply helps to associate accounts to the same user.
I would also create a table for Accounts and use the account_id as a foreign key for all your customer information that may change between accounts. Each row in the Accounts table will be owned by a customer from before.
So the relationship between customers and accounts would be one to many, and the relationship between accounts and "account specific customer info" would be one to one.

Different Users role , each in one table

in my database i have admins , merchants and drivers .
All of them share many attributes like name/email/phone/credentials..etc
So , the way i designed my database is a tabled called "users" and table for each role [admin,merchant,driver] where shared attributes are stored in users table.
My questions is do i have to maintain an ID for each role for example [ driver_id , merchant_id ] and link it to the user_id or depending only on the user_id and storing the type of the user in users table ?
Depending on the type of queries you'll run on your database, you could have a few different options. If you're going to query the user table without needing information from the role-specific tables, then just store the type of user i.e. role in the users table.
However, if you are going to be including role-specific information that is in the admin, merchant, or driver tables, then it may be beneficial to include a unique merchant_id, admin_id or driver_id in the user table to designate a role and simultaneously act as ID into the appropriately associated table.
Diagramming this in database modeling software can help to identify the relationships between different data pieces within your application to better design your tables and attributes.

Using Multiple Databases

A company is hired by another company for helping in a certain field.
So I created the following tables:
Companies: id, company name, company address
Administrators: (in relation with companies) id, company_id, username, email, password, fullname
Then, each company has some workers in it, I store data about workers.
Hence, workers has a profession, Agreement Type signed and some other common things.
Now, the parent tables and data in it for workers (Agreement Types, Professions, Other Common Things) are going to be the same for each company.
Should I create 1 new database for each company? Or store All data into the same database?
Thanks.
Since "Agreement Types", "Professions" are going to be same for each company, I would suggest to have a lookup table like "AgreementTypes" with columns such as "ID", "Type" and refer "ID" column in "Workers" table. I don't think new database is required, relational databases are used to eliminate data redundancy and create appropriate relationships between entities.
By imagining having one database for one company, it ends up with having one record in "Company" table in each database. "Administrators" & "Workers" are associated with that single record. And other common entities such as "AgreementTypes" will be in other tables.
So, if there is any addition/modification to agreement type, it is difficult to do it in all databases. Similarly, if there is any new entity to be linked to "Company" entity, again all databases needs to be revisited based on assumption that these entities belong to ONE application.
You should have one single database, with a structure something like this (this is somewhat over-simplified, but you get the idea):
Companies
CompanyID PK
CompanyName
CompanyAddress
OtherCompanySpecificData
Workers
WorkerID PK
CompanyID FK
LastName
FirstName
DOB
AgreementTypeID FK
ProfessionID FK
UserID FK - A worker may need more than one user account
Other UserSpecificData
Professions
ProfessionID PK
Profession
OtherProfessionStuff
AgreementType
AgreementTypeID PK
AgreementTypeName
Description
OtherAgreementStuff
Users
UserID PK -- A Worker may need more than 1 user account
WorkerID FK
UserName
Password
AccountStatus
Groups
GroupID PK
GroupName
OtherGroupSpecificData
UserGroups --Composite Key with UserID and GroupID
UserID PK
GroupID PK
Obviously, things will grow a little more complex, and I don't know your requirements or business model. For example, if companies can have different departments, you may wish to create a CompanyDepartment table, and then be able to assign workers to various departments.
And so on.
The more atomic you can make your data structures, the more flexible your database will be as it grows. Google the term Database Normalization, and specifically the Third Normal Form (3NF) for a database (Considered the minimum for efficient database design).
Hope that helps. Feel free to elaborate if you are stuck - there is a lot of great help here on SO.

Normalizing Foreign Keys with Junction & Lookup Tables

I've been scratching my head lately over the relationship between database normalization and foreign keys with respect to junction tables and lookup tables.
I’ve currently have the following tables: Users, UserTypes, Roles, UsersInRoles, and Permissions. UserTypes is simply a lookup table providing the name of the type, with description, via a foreign key in the Users table. Roles are the various roles with associated Permissions linked to each User via the UsersInRoles table.
I need to come up with a structure that allows me to provide multiple Roles for each User, in addition to special permissions for each respective User that may not be covered in the fixed Roles of which they are a member.
I had a foreign key to my UsersInRoles table from the Users table, but decided that it just didn’t make sense. Conversely, it seems to make perfect sense to use a foreign key from the Users table to the UserTypes table. Is this the rule of thumb? That junction tables have foreign keys linking to the primary keys of the tables it joins, while master tables have foreign keys linking to the primary key of associated lookup tables?
Parameters:
Each User can have one or multiple Roles
Each Role has a fixed set of Permissions
Each User can have additional Permissions not provided by their Roles
I suspect I may also need a PermissionsInRoles junction table as well as one for PermissionsInUsers? But this is just ridiculous isn't it? There just must be a better way. I'm thoroughly convinced that I'm losing my mind here, lol. Any help would be greatly appreciated. This has got my head spinning :P
UPDATE
Is this basically how it would be setup? I might get rid of the UsersInRoles table so each user can only be in one role, and additional permissions can be added via the SpecialPermissions junction table. From a UI standpoint, I was thinking it might be good when assigning permissions to a user, selecting a "Role" would simply check the appropriate boxes associated with that role, then you customize that and submit. That way I think I would only need a junction table between the Users and Permissions tables perhaps? Ugh. This is quite daunting for a first time database designer haha. Remember when you were just starting out? Or maybe you guys are more of a genius than I am, lol.
Schema Image link (can't post images yet)
Here's a neat scholarly article (albeit 10 years old) on query-driven database design titled: "Robust Database Design for Diverse Query Patterns". The Conclusion section has an interesting approach.
I suspect I may also need a PermissionsInRoles junction table as well
as one for PermissionsInUsers?
Well, you already said one of the requirements was "Each Role has a fixed set of Permissions". So to fulfill that requirement, you need to store permissions that apply to each role.
Table: role_permissions
PK: (Role, Permission)
Role Permission
--
User Create
User Update
Admin Create
Admin Update
Admin Delete
You don't need two different tables to implement that requirement.
By the same token, you've already said "Each User can have additional Permissions not provided by their Roles". To fulfill that requirement, you have to store user-specific permissions.
Table: user_permissions
PK: (username, permission)
username permission
--
user1 Rename
user1 Leak to News of the World
user2 Randomly corrupt data
So, again, you don't need two different tables to implement that requirement. Both those tables are in 5NF.
But this is just ridiculous isn't it?
What's ridiculous?
That you have very elaborate requirements for permissions?
That you store business data (like permissions) in tables?
That it takes more than one table to model your permission requirements?
Something else?
If you want specific advice about your actual tables, edit your question and insert DDL for your tables.
Later
I looked at your diagram. Not every table needs an id number; id numbers have nothing to do with normalization.
If I were designing your system, I probably wouldn't use id numbers in the tables Roles, Permissions, and UserTypes until I saw a performance problem that id numbers could fix. (In most systems over the last 30 years, that means, well, almost never.) Before I used an id number, I'd also consider and test using a human-readable code instead. Human-readable codes often don't require joins; id numbers always require joins.
In most SQL dbms, you can combine a data type and check constraint in a CREATE DOMAIN statement. In PostgreSQL, you might use something like this to reduce the number of tables.
CREATE DOMAIN role AS VARCHAR(7) NOT NULL
CHECK (VALUE in ('Admin', 'User', 'Guest'));
Followed by
CREATE TABLE user_roles (
user_id integer not null references users (id),
role_name role
);
Replacing a table with a CREATE DOMAIN statement is most useful when the number of rows is stable and relatively small. Personally, I'd rather have the tables.
If you stick with id numbers, you also need UNIQUE constraints on Roles.RoleName, Permissions.Description, and UserTypes.UserType.
Otherwise, you seem to be doing fine.
If your securables are just a products table (or set of tables), and you're using SSMS (SQL-Server Management Studio) then you should not be inventing your own security schema from scratch.
What I would recommend is that you setup your users and roles in SSMS -- expand the Database, then --> Security --> Users, etc. Right-click a user, look for securables, and then you can assign the user to roles, or also, just objects (tables, etc.) directly. Or right-click roles and you have similar options. Whatever you do, stay away from creating your own security schema, if you can help it.
If you need your web app to have access to the database, then look into "utility accounts" (these are like users, created at the server level instead of the database level, but then you can bring them into your database from there.); or look into impersonation if you're able to pass users' creds from your internal network when they login to the database. Utility accounts or users can be assigned to roles, or granted direct access to database objects without roles -- whatever you need.
One thing I've done before, in a similar-sounding scenario:
Keep Roles and users in the same table.
Have an objects table (the tables/queries/forms/etc. you will be granting permissions to)
Have a permission table -- this is where you will link roles/users to objects (i.e., John can SELECT on table 1)
Finally, have an Inheritance table -- this is where you will link roles/users to each other (i.e., John has permission to do whatever Role1 can do)
For example -- a structure like this:
For example:
Users Table:
UserID -- User -- UserTypeID
1 ------- John Smith --- 1
2 ------- Sally Fort --- 1
3 ------- Public Role -- 2
4 ------- Special Role - 2
UserType Table:
UserTypeID -- Description
1 ----------- Human Being
2 ----------- Role
Objects Table:
1 -- Data-Entry Form 1
2 -- Data-Entry Form 2
3 -- Query 1
4 -- Table 1
Permissions Table
UserID -- ObjectID -- Permission
1 -- 1 -- Update (This says John can Update Data-Entry Form 1 (via direct permission))
3 -- 1 -- Update (This says that the Public Role can Update Data-Entry Form 1)
3 -- 2 -- Update (...as well as Data-Entry Form 2)
4 -- 3 -- Select (This says that the special role can Select from Query1)
4 -- 4 -- Insert (...the special role can Insert into Table1)
Permission Inheritance Table
UserID -- UserID_ToInheritFrom
1 -- 3 (this says John can do whatever the Public Role can do)
1 -- 4 (this says John can do whatever the Special Role can do)
2 -- 3 (this says Sally can do whatever the Public Role can do)
So then if you wanted to query, "What can John do?", you'd do something like this:
SELECT
ObjectID,
Permission
FROM
PermissionsTable
WHERE
UserID = 1 -- John has direct permission
OR UserID IN (SELECT UserID_ToInheritFrom FROM PermissionInheritanceTable WHERE UserID = 1)
-- John has indirect permission via the Permission Inheritance Table (or you can call it the "role
-- membership table" if that's easier for you to think of that way.)
This implementation works well. If you want to see a similar implementation, look at SQL-Server's implementation (or better yet, USE it, instead of re-creating the wheel from scratch.)

How to model this one-to-one relation?

I have several entities which respresent different types of users who need to be able to log in to a particular system. Additionally, they have different types of information associated with them.
For example: a "general user", which has an e-mail address and "admin user", which has a workstation number (note that this a hypothetical case). Both entities also share common properties like first name, surname, address and telephone number. Finally, they naturally need to have a (unique) user name and a password to log in.
In the application, the user just has to fill in his user name and password, and the functionality of the application changes slightly according to the type of the user. You can imagine that the username needs to be unique for this work.
How should I model this effectively?
I can't just create two tables, because then I can't force a unique constaint on the user name.
I also can't put them all in just one table, because they have different types of specific information associated to them.
I think I might need 3 seperate tables, one for "users" (with user name and password), one for the "general users" and another one for the "admin users", but how would the relations between these work? Or is there another solution?
(By the way, the target DBMS is MySQL, so I don't think generalization is supported in the database system itself).
Your 3 tables approach seems Ok.
In users table have only ID, username, password,usertype.
In general users table have ID, UserID (from users table), other fields.
Same thing for admin users.
Usertype field will tell you from what table to search for additional info
if(usertype==admin)
select * from admins where userid=:id;
else
select * from general where userid=:id;
Two tables. USERS with user names, first, last, etc. ROLES with roles, and a link back to the user name (or user id or whatever). Put a unique constraint on the user name. Put workstation nbr, email, phone, whatever else you need, in the user table. Put 2 columns in the ROLES table -- USERID and ROLE.
You should decide how much specific information is being stored (or likely to be stored in the future) and make the decision based on that. If there are only a handful of fields for each user type then using a single table is alright.
USERS table (name, type, email, password, genfield1, genfield2, adminfield1, adminfield2)
Make sure to include the type (don't assume because some of the fields particular to that user are filled in that the user is of that type) field. Any queries will just need to include the "AND usertype = " clause.
If there are many fields or rules associated with each type then your idea of three tables is the best.
USERS table (ID, type, name, password)
GENUSERS (ID, genfield1, genfield2)
ADMINUSERS(ID, adminfield1, adminfield2)
The constraints between IDs on the table are all you need (and the main USERS table keeps the IDs unique). Works very well in most situations but reports that include both types of users with their specific fields have to be done in two parts (unioned SQL or subqueries or multiple left joins).
You can solve it with one 'general' users table containing the information thats available for all users and 1 table for every specific user type. In your example you will then need 3 tables.
Users: This table holds only information shared between all usertypes, ie. UserId, Name, Address, etc.
GeneralUsers: This table 'extends' the Users table by providing a foreing key UserId that references the Users table. In addition, information specific to general users are held here, fx. EmailAddress, etc.
AdminUsers: As with GeneralUsers, this table also 'extends' the Users table by providing a foreign key UserId referencing the Users table. In addition information specific to admin users are held here, fx. WorkstationId, etc.
With this approach you can add additional 'specializations' if the need arises by simply adding new tables that 'extends' the Users table using a foreign key reference. You can also create several levels of specialization. If for example admin users are general users as well as admin users then AdminUsers could 'extend' GeneralUsers instead of Users simply by using a foreing key to GeneralUsers instead of Users.
When you need to retreive data from this model you need to which type of user to query. If for example you need to query a GeneralUser you will need something similar to:
SELECT * FROM GeneralUsers
LEFT JOIN Users ON GeneralUsers.UserId = Users.UserId
Or if querying an admin user
SELECT * FROM AdminUsers
LEFT JOIN Users ON AdminUsers.UserId = Users.UserId
If you have additional levels of specialization, for example by having admin users also being general users you just join your way back.
SELECT * FROM AdminUsers
LEFT JOIN GeneralUsers ON AdminUsers.UserId = GeneralUsers.UserId
LEFT JOIN Users ON GeneralUsers.UsersId = Users.UserId
I most definitely would not do a model where you have separate tables as in GeneralUser, AdminUser and ReadOnlyUser.
In database design, a good rule of thumb is "Down beats across". Instead of multiple tables (one for each type), I would create a SystemUsers table, and a Roles table and define a join table to put SystemUsers in Roles. Also, I would define individual roles.
This way, a user can be added to and removed from multiple roles.
A role can have multiple permissions, which can be modified at any time.
Joins to other places do not need a GeneralUserId, AdminUserId and ReadOnlyUserId column - just a SystemUserId column.
This is very similar to the ASP.Net role based security model.
alt text http://img52.imageshack.us/img52/2861/rolebasedsecurity.jpg

Resources