User and Profile - Which Gets The Foreign Key To The Other? - database

The User table contains administrative info like username, password, and email.
A Profile has all the other information like about me, names, social network URLs, etc.
A profile isn't required. (A profile isn't created until the user fills in profile info and saves it).
So, I've seen 2 implementations:
Only User has a ProfileId FK to Profile - ProfileId is nullable and has a SET NULL delete rule.
Only Profile has a UserId FK to User - UserId is required, thus, non-nullable, and the DELETE CASCADE delete rule.
I don't think they're equivalent. Where would each situation fit better when a user doesn't always have to have a profile associated with it?

After much searching and a few discoveries, Profile gets the UserId FK based on the Principal/Dependent concept.
User is the principal because it can exist independently without even knowledge that a profile exists. The Profile is the dependent, which bears the foreign key column, and it being dependent means it can't exist until the User is created to give its newly-generated Id to Profile's UserId.

Related

Two foreign keys from one table

I am trying in following DB ERD that User creates a Profile. A user can see his followers as well as the profiles that users are following.
The problem is:
Both sections either "Followers" or "Following" are users not Profile
Update:
Is the following approach okay or in above diagram?
SQL> Create table users(
2 user_id number(5) primary key,
3 reg_date date,
4 name varchar2(50),
5 password varchar2(50));
Table created.
SQL> Create table Follow(
2 follow_id number(5),
3 following number(5) constraint User_fk references users(user_id),
4 follower number(5) constraint User_fk1 references users(user_id));
Table created.
Please advise. Thanks in anticipation
Should Profile be an entity/table separated from User, or should they be merged?
This depends on your requirements. If a user has just one profile (as on many sites, e.g. on this one), the profile doesn't need to be a separate entity. Then the question whether the following relationship should point to users or to profiles vanishes. If, however, a user can have more than one profile (which might be guessed from your FK type_id), let's say one for his sports and another for his musical interests, then two entities and tables are needed.
Should Follower point to User or to Profile?
In the case of just one User entity, follower and following must both point to User, as there is nothing else. This is your SQL solution.
In the case of a separate Profile entity, it's again up to your requirements. Should the follower follow the user as a whole, or is he just interested in a certain profile angle of the user? (Follow Jack, or follow Jack as a sportsman, but not as a musician.) In the first case, following points to the User, otherwise to the Profile.

Database schema about social networking like Facebook

Like Facebook, I have posts, comments and user profiles.
I THINK THAT
Posts and comments do not need the details of user
ONLY user profiles need the details
So I separate the user information into main and detail
Here is the schema.
Question
Is it necessary to separate user data into main and details?
WHY not or WHY yes?
Thanks for applying!
I would recommend using separate tables because you may not need all that information at one time. You could do it either way but I think of it as do you need all of the data at once.
Table 1 (User Auth)
This table would hold only information for log-in and have three columns (user_name, hashed_password, UID)
So your query would select UID where user_name and hashed_password matched. I would also recommend never storing a readable password in a database table because that can become a security issue.
Table 2 (Basic Information)
This table would hold the least amount of information that you would get at signup to make a basic profile. The fields would consist of UID, name, DOB, zip, link_to_profile_photo, email and whatever basic information you would like. email is kind of special because if you require the user_name to be an email address there is no reason to have it twice.
Table 3 (Extended Information)
This table would hold any optional information that the user could enter like phone_number, bio or address assigned by UID.
Then after that you can add as many other tables that you would like. One for Post, one for comments, ect.
An Example of a Post table would be like:
post_id, UID, the_post, date_of_post, likes, ect.
Then for Comments
comment_id, for_post_id, UID, the_comment, date_of_comment, likes, ect.
Breaking it down in to small sections would be more efficient in the long run.
Database performance is associated with disk seek time. Disk seek time is a bottleneck of database performance. For large table, you may need large seek time to locate and read an entry. As for post and comments you do not need user details, just user main info, you may get reduced read time when you read only user Id for post and comments. Also joins with user_main_info will be faster. You may keep the smallest portion of data you need to read most frequently on one table and other detailed information on another table. But, in a scenario like when you will always need to read all the user information together, this won't give you any benefit.
1)the userinformation table will be added
ex:create table fb_users
(intuserid primary key,
username varchar(50),
phoneno int,
emailid varchar(max))
2)the sending of the friend request would be
2.a)create the table name called friends, friend requestor, friend requested by, status b/w both of them, Active flag
ex:create table fb_friends
(intfriendid primary key,
intfriendrequestor int (foreign key with fb_users's(intuserid)),
intfriendrequestedby int (foreign key with fb_users's(intuserid)),
statusid varchar(max)(use the status id from the below table which is a look up table),
active bit)
3)creating the table for the status the status
3.a)create the table name called status, statusname, statusdesc, Active flag
ex:create table fb_staus
(intstatusid primary key,
statusname varchar,
statusdesc varchar,
active bit)
the status could be
pending
approval
deleted
..etc
4)similarly for creating the groups,likes,comments also
a table will be created respectively for each one of them and the foreign key of the intuserid from user table
are linked for each of them

Database design, shound I use varchar for Primary Key in this case?

Im building a webpage where users will be able to create accounts, and every account will have its own subdomain. So there could be URL-s like this:
www.user1.domain.com
www.user2.domain.com
...
They will have their own pages too, like this:
www.user1.domain.com/url-1/
www.user1.domain.com/url-2/
www.user2.domain.com/url-3/
...
So I need to store account_url and page_url in database.
I did it like this, I have users, accounts and pages tables.
This is how my tables look like:
USERS:
user_id PK
user_name
user_pass
...
ACCOUNTS:
account_id PK
user_id FK
account_url
account_name
account_type
...
PAGES:
page_id PK
user_id FK
page_url
page_name
page_content
...
Now the problem is this, since I get url like this:
www.user1.domain.com/page-url/
The only information I can fetch from url is account_url and page_url since its in URL, dispatcher/router gets these two variables. account_url is subdomain, and page_url is segment after domain.
Since there will be multiple users I always need to get that user_id so I can update/delete rows that belong to them. So I need to update page_content where user_id belongs to this user and page_url is the one from URL.
But I dont have user_id. And when I would like to update page_url_content, first I need to find user_id, like this:
SELECT user_id FROM accounts WHERE account_url = something
And then when I have user_id I can update content of a page or do any other action.
So is this a good design?
Its normalized and clean, but when Im using this in every action inside controller I need to fetch user_id first joust to be able to do a real query I wanted.
Now, I could use account_url for Primary Key, and have all tables relate to that primary key. So when I get URL I already know the Primary key since its in the URL.
Is this a good case to use Primary Key in URL, or Im doing something wrong?
I prefer to always have my primary ID keys as integers for joins. That said, there are a bunch of ways to help make your site snappy.
You could index the account_url column so look ups are more efficient.
Or you could cookie the users ID and use that value instead of querying the database each time. Granted, you would want to do some session tracking so someone can't spoof someone else.
One presumes the user will be in control of the name of the subdomain, so embedding the user ID into the subdomain name probably wouldn't be effective otherwise it is also an option.
You could keep user ID and user account_url in a separate table and cache that table so you don't hit the database for the vast majority of lookups.
My recommendation would be to keep the primary key the integer, index the account_url and identify a page load target time; say completing all database access and page rendering in under 1.500 seconds. When your site starts to respond over your threshold, then you can analyze your site to see where the actual problems lie and address them then.
In general, leave the database normalized as much as possible. If and when you can provably show (using metrics and actual measurements) that you need to denormalize for performance reasons, then think about doing that.
In this case, if you have a m-1 relationship between a domain and a user's account, you can effectively treat the domain as a user ID; you just have to join things in the right way. (and by m-1, I mean a single domain can only be "owned" by 1 user).
The key thing is that you don't need to get the user_id because you can get to it by joining the ACCOUNTS table as needed since it ties the domain to the user_id.
Lastly, to your question about using the domain as the primary key, you can do this, since a domain is required to be "unique", but you have a minimal overhead and much more flexibility by using a surrogate primary key.
You have two totaly separate issues. Mapping Subdomains and pages to a user is the easier of the two. The more difficult issue is "State". You need to create state database (or similar module) to keep track of which user is currently logged in and if they are still logged in when an update is received.
JZ touched on this in his comment. Don't confuse these two issues, they are separate and should betreated as such.

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

How to determine where to place the foreign key in this scenario?

If I have two tables - Logins and Users, as follows:
Logins
LoginIdNo
UserIdNo
HashedPassword
Users
UserIdNo
LoginIdNo
Username
Each login "has a user" and each user "has a login" but which "belongs to" which?
Is it simply a judgment call or is there a clearcut formula for determining where the foreign key should reside?
This is a one-to-one relationship. Where you put the foreign key is probably decided by optionality in those cases.
Is there any particular reason you've split this into two entities? I'm not a huge fan of one-to-one mappings, particularly on ORMs like JPA where they're awkward to implement (if you use the primary key from one as the foreign key to another).
What, in your system, is the difference between a Login and a User?
If Login were to happen each time a user logins in (ie it's an audit trail of user activity) then you have a one-to-many relationship between User and Login and Login should use a UserID foreign key.
But in this case where the username is in one table and the password is in another and there's a one-to-one relationship betwene the two you have to ask why they're separated.
Since a Login will never be associated with more than one User (and vice-versa), it is an arbitrary decision of how you define the relationship (and therefore where you place the Foreign Key). Unless you are also going to add other attributes (Firleds) or use Roles, it might be simpler to simply define it like so:
Users
UserIdNo
Username
HashedPassword

Resources