how to maintain friend requests data in sqlserver - sql-server

I have a requirement in my app where one user can send the friend request to another user. We use SQL Server database as the backend. The structure of the table is like this.
CREATE TABLE FriendStatus
(FriendStatusId BIGINT PRIMARY KEY IDENTITY(1,1),
FromUserId BIGINT,
ToUserId BIGINT,
StatusId TINYINT,
SentTime DATETIME2,
ResponseTime DATETIME2);
I have few questions related to this:
If user A sends a friend request to user B, then the friend request from user B to User A should still valid ? I feel that should be the case, let me know if there is a better way of handling this ?
Is it a good idea to store the users data in a separate table called friends table once User b approves user A friend request ? And Once User B approves User A request then two records needs to be inserted into the friends table with col1 containing user A and col2 containing user B .At the same time should we also insert a record with User B in col1 and USer A in col2 ? Or two records are unnecessary ?

Is it a good idea to store the users data in a separate table called friends table once User b approves user A friend request ?
No, it's almost never a good idea to duplicate data in your database. You can get anomalies where the same data in two places has two different values. Which value is the correct value?
Here's one way to maintain the relationship
User
----
User ID
User Name
...
Friend
------
User ID 1
User ID 2
...
In the Friend table, the primary key is (User ID 1, User ID 2). You would also have a unique index on (User ID 2, User ID 1). It's up to you if you want to have one row or two rows for each relationship.
One row means you have to do two SELECTS with a UNION. One SELECT using the primary key and one SELECT using the unique index.
Two rows means you do a SELECT using the primary key.
You have the same one row / two row choice with the FriendRequest table.
FriendRequest
-------------
User ID 1
User ID 2
Status
Sent Time Stamp
Accepted Time Stamp
...
You can have one row or two rows for each request. In this case, I'd prefer the one row because I could determine which user initiated the friend request.

I'll take a few examples from Facebook to answer.
If user A sends a friend request to user B, then the friend request
from user B to User A should still valid?
No, a dialog box appears You have already recieved a Friend Request from {name}. Also from B's view, The link to Send Friend Request to A should be changed to Respond to friend request with a respective code.
Is it a good idea to store the users data in a separate table called friends...?
No, one record is enough. Additionally you can have a new column to maintain status status={blocked|friends|pending}
Well thats my idea. You are free since the application is yours. Think as a user too.

Related

Best way to interconnect data to lower db queries [generic, no language specific]

I'm making a bot that receive and send images, i have to keep track to which image is sent to who so it send it only once. An user can also flag the image as inappropriate.
I made a db with 2 tables:
userTable with userID and userName
imageTable with imgID, fileName, fileCRC
I can think only of:
a) add viewedBy to imageTable "user1,user213,user9"
or
b) add imageToView to userTable "123,545,21321,654565"
But if I do [a] there is the problem that the more images a user views the more time is needed to get one random image.
And if I do [b] I already have a list of unseen images so I can just pick one random from here then delete the id. But if one user flag it as inappropriate I have to loop/remove the id from all the user in the db...
There is any better way?
You need an intermediate table that keeps track which user has seen which image. So basically this new table, let’s call it imageByUser, would contain a user id, an image id, inappropriate boolean flag, dateseen datetime (optional but would be useful on the long run) and a generated primary key (or you can have the combination of the user, the image and the dateseen as a composite logical primary key instead).
Having this third table would solve all your problems as you would just add a new row when someone sees an image. Also if they mark it as inappropriate m all you have to do is update the inappropriate flag to yes. This way you could even keep track of the cases when a user happens to see the same image twice (just add another row to the table).

Either of 2 columns is always redundant -- is there a better solution?

Say, I want to create a form for a feedback. If a registered user submits a feedback, his email address is used automatically because he's authenticated. If an anonymous user does that, he has to enter his email manually. My table would look like this:
feedbacks(id, user_id, email, body)
As you can see, it has a redundant column: either user_id or email. And for those who's not familiar with the database structure it'll be confusing: why both email and user_id? can they both be null? or both have a value at the same time? in reality, only one of them must have a value, which isn't possibly to achieve on database level using constraints. Also, what if I by mistake insert values in both columns?
Thus, I wonder, is there any way to change its structure so that it's more wise and that issue described above has become resolved? Using a trigger isn't what I'm looking for.
In other words, the issue is "either of 2 columns is always redundant".
If you had several mutually exclusive columns, then you might have a good case for something called entity sub-typing. As it is, there is no good design reason for adding all of the extra overhead of this design pattern.
These are the basic options that you have:
Two mutually exclusive columns in one table - This is your current design. This is a good design because it lets you define a proper foreign key constraint on your user_id. You mention that it may be confusing for people that don't know the database well because the same kind of information might appear in one or the other place in the table. However, it's important to remember that even though both columns contain a string that happens to be in the form of an email address, to your system these things are semantically distinct. One is a foreign key to your user table. The other is a means of contacting (or identifying?) a non-member. You could avoid this apparent confusion in one of two ways: (a) give a more descriptive name to your email column, such as non_member_email or (b) create a view that coalesces user_id and email into a single column for displaying this information to people who would otherwise be confused.
Entity Subtyping - This approach has you create separate tables for logically separate groups of predicates (columns). These are joined together by a supertype table which gives a common primary key for all logical subtypes, as well as holding all other common predicates. You can google around to learn more about this design pattern. As I've already mentioned, this is overkill for your case because you only have one pair of mutually exclusive columns. If you think it's confusing to have this then having three tables (supertype, member subtype, non-member subtype) will really be confusing.
Column Overloading - This approach would have you combine both columns into a single one. This is feasible because you only need room in your table for one email address at a time. This is a terrible idea because it prevents you from creating a declarative referential constraint on user_id which is a very important tool for maintaining your data's referential integrity. It also conflates two semantically different pieces of information, which violates good database design principles.
The best choice is number 1. Don't worry about having two mutually exclusive columns or if you think you can't "comment" your way around the confusion you think this might cause with more descriptive column names, then use a view to hide the "complexity" of storing two things that look similar in two separate columns.
If one must be exclusively filled:
create table feedbacks (
id integer,
user_id text,
email text,
body text,
check ((user_id is null)::int + (email is null)::int = 1)
);
The cast from boolean to integer yields either 1 or 0, so the sum must be 1.
Remove the email field. If the user is registered, enter their user_id as you do now. If the user is not registered, search the user table for an anonymous entry with that email address. If exists, use that user_id. Otherwise, create an entry in the user table named 'Anonymous', storing the address and use the newly created user_id. There are two advantages:
You don't need mutually exclusive fields. As you have already noticed, these can be the cause of a lot of confusion and extra work to keep the data clean.
If an anonymous poster later registers, the existing "anonymous" user entry can be updated, thus preserving the user_id value and preserving all feedback (and any other activity you track for anonymous users) entered before registering. That is, if a user anonymously enters a few feedbacks then registers, the previous feedbacks remain associated with the now named user.
I might misunderstand the question, but why you say it is impossible to do with constraints?..
t=# CREATE TABLE feedbacks (
t(# id integer,
t(# user_id text CHECK (case when email is null then user_id is distinct from null else user_id is null end),
t(# email text CHECK (case when user_id is null then email is distinct from null else email is null end),
t(# body text
t(# );
CREATE TABLE
t=# insert into feedbacks select 1,null,null,'t';
ERROR: new row for relation "feedbacks" violates check constraint "feedbacks_check1"
DETAIL: Failing row contains (1, null, null, t).
t=# insert into feedbacks select 1,'t','t','t';
ERROR: new row for relation "feedbacks" violates check constraint "feedbacks_check1"
DETAIL: Failing row contains (1, t, t, t).
t=# insert into feedbacks select 1,'t',null,'t';
INSERT 0 1
t=# insert into feedbacks select 1,null,'t','t';
INSERT 0 1
t=# select * from feedbacks ;
id | user_id | email | body
----+---------+-------+------
1 | t | | t
1 | | t | t
(2 rows)

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

Realizing Three States By Storing Values in Single Column In DB Table

I Have List of Products Displayed in Web Page.
Each product is identified by unique product id in database.
Initially when the page loads its would be shown as Both tick and Cross under every product (Image 1)
Once the User click Tick Symbol for particular product I will display it as Interested (Image2)
When the User click Cross Symbol for particular product I will display it as Not Interested (Image3)
I should load the user last selected preference every time the page loads by storing the user name and productId for which the user is Interested.
This remains simple when there are only two states where the user might either be interested or not interested since i will store all the interested ProductaIds in DB and Use them to load user preference.That is I will apply class Interested for all the ProductIds which are in DB and NotInterested class for all those Ids which are not In database.
Now the third state is the one for which the user never touched - Image1.
I already have a DB Table Like Below
CREATE TABLE UserPreference(
UserId INT,
Interested_ProductsId VARCHAR(150)
);
I am Storing the Interested_ProductsId as CSV Product Ids (i.e) 5,75,2,15 are all product Ids
Now my question is it possible to realize the third state(Image1) in the CSV.I am storing only ProductsIds in which customer interested.How to realize the ProductsId in which customer is Not interested(Image3) and customer never clicked(Image1).
Thanks in Advance
Yes this is possible: Introduce a new column:
Type tinyint not null
CHECK (Type in (1, 2, 3))
And define type as one of your three states.
You can associate arbitrary data with your join table items. You basically promote them to "entities" that way.

how are viewing permissions usually implemented in a relational database?

What's the standard relational database idiom for setting permissions for items?
Answers should be general; however, they should be able to be applied to example below. Anything flies: adding columns, adding another table—whatever as long as it works well.
Application / Example
Assume the Twitter database is extremely simple: we have one User table, which contains a login and user id; we have a Tweet table, which contains a tweet id, tweet text, and creator id; and we have a Follower table, which contains the id of the person being followed and the follower.
Now, assume Twitter wants to enable advanced privacy settings (viewing permissions), so that users can pick exactly which followers can view tweets. The settings can be:
Everyone on Twitter
Only current followers (which would of course have to be approved by the user, this doesn't really matter though) EDIT: Current as in, I get a new follower, he sees it; I remove a follower, he stops seeing it.
Specific followers (e.g., user id 5, 10, 234, and 1)
Only the owner
Under these circumstances, what's the best way to represent viewing permissions? The priorities, in order, are speed of lookup (you want to be able to figure out what tweets to display to a user quickly), speed of creation (you don't want to take forever to post a tweet), and efficient use of space (every time I post a tweet to everyone on my followers' list, I shouldn't have to add a row for each and every follower I have to some table.)
Looks like a typical many-to-many relationship -- I don't see any restrictions on what you desire that would allow space savings wrt the typical relational DB idiom for those, i.e., a table with two columns (both foreign keys, one into users and one into tweets)... since the current followers can and do change all the time, posting a tweet to all the followers that are current at the instant of posting (I assume that's what you mean?) does mean adding that many (extremely short) rows to that relationship table (the alternative of keeping a timestamped history of follower sets so you can reconstruct who was a follower at any given tweet-posting time appears definitely worse in time and not substantially better in space).
If, on the other hand, you want to check followers at the time of viewing (rather than at the time of posting), then you could make a special userid artificially meaning "all followers of the current user" (just like you'll have one meaning "all users on Twitter"); the needed SQL to make the lookup fast, in that case, looks hairy but feasible (a UNION or OR with "all tweets for which I'm a follower of the author and the tweet is readable by [the artificial userid representing] all followers"). I'm not getting deep into that maze of SQL until and unless you confirm that it is this peculiar meaning that you have in mind (rather than the simple one which seems more natural to me but doesn't allow any space savings on the relationship table for the action of "post tweet to all followers").
Edit: the OP has clarified they mean the approach I mention in the second paragraph.
Then, assume userid is the primary key of the Users table, the Tweets table has a primary key tweetid and a foreign key author for the userid of each tweet's author, the Followers table is a typical many-to-many relationship table with the two columns (both foreign keys into Users) follower and followee, and the Canread table a not-so-typical many-to-many relationship table, still with two column -- foreign key into Users is column reader, foreign key into Tweets is column tweet (phew;-). Two special users #everybody and #allfollowers are defined with the above meanings (so that posting to everybody, all followers, or "just myself", all add only one row to Canread -- only selective posting to a specific list of N people adds N rows).
So the SQL for the set of tweet IDs a user #me can read is, I think, something like:
SELECT Tweets.tweetid
FROM Tweets
JOIN Canread ON(Tweets.tweetid=Canread.tweet)
WHERE Canread.reader IN (#me, #everybody)
UNION
SELECT Tweets.tweetid
FROM Tweets
JOIN Canread ON(Tweets.tweetid=Canread.tweet)
JOIN Followers ON(Tweets.author=Followers.followee)
WHERE Canread.reader=#allfollowers
AND Followers.follower=#me

Resources