what are the table structures of your tables: Users and Friends ?
AW
Main Topics
Browse All TopicsOK, so I have a table that looks like this:
FriendId (int) | UserId (int)
This basically provides a way to track the relationship between a user and their friends... like myspace or friendster.
Now each time I add a friend i only add one entry. Say the user id = 9 and friend id = 7, so it would look like this:
FriendID UserId
7 9
So now i want to display the users friends. their friends can be either added by the friend or the user, there my query needed to look like this:
Here is a simplified version:
SELECT * from Friend A
left JOIN user B ON B.UserId = A.FriendId
LEFT JOIN Image C on B.MainImgId = C.ImageId
WHERE A.UserId = @userid OR A.FriendID = @UserID
This is problimatic, as I'm sure you can see. The problem is that
1) it pulls duplicate records
2) it shows the user as a friend because that satifies it conditions.
Can you offer a better way to write this simple query??
Thanks!!
-- jenni
This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.
Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.
If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.
Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.
Access the answers to your technology questions today.
30-day free trial. Register in 60 seconds.
Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Try it out and discover for yourself.
30-day free trial. Register in 60 seconds.
Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.
From the looks of it you have a main user table (User) which containts User info + a pointer to their Image in the Image table.
Now if you want to just display the user's friends only then
SELECT * from Friend A
left JOIN user B ON A.FriendId = B.UserId
LEFT JOIN Image C on B.MainImgId = C.ImageId
WHERE A.UserId = @userid;
You don't need to friend in the where clause and I would swap round the left join on user for completeness.
Now if you wanted to display the friends list of the user's friends you would have to traverse the table like a bill of materials.
First, user and image are reserved words in SQL Server - so I added brackets [ ] around the table names as shown below
Next, I moved the [User] table to the top of the join list as the base table (assuming they should always exist in the [User] table)
Then, I modifed the where clause to join to B.UserId ([User] table) (assuming the UserId was not in the Friend table - FriendId = UserId)
Also, removed FriendId from the WHERE clause.
This seems to work:
DECLARE @USERID INT
SET @USERID = 6
SELECT *
FROM [User] B
LEFT OUTER JOIN [Friend] A ON B.UserId = A.FriendId
LEFT OUTER JOIN [Image] C ON B.MainImgId = C.ImageId
WHERE B.UserId = @userid
I'm not sure if I explained my problem correctly.
So lets say
UserID 7 = Jenni
UserId 9 = Samantha
UserId 14 = Ryan
I run this query to determine who is friend's with Jenni. If Jenni added Samantha and then Ryan adds Jenni the results look like this:
UserID FriendID
7 9
14 7
So, when I show this persons friends I am pulling the "FriendId". the method I am currently using will show Jenni's friends as Samantha and Jenni.
Thats not right. Jenni's friends are Samantha and Ryan. Now, I could create two records for each friend relationship. But that seems redundant. I am using this with ASP.NET so maybe there is a way to filter a dataset or something but I'd prefer to do it in the query.
IF you wanna see what the friend system looks like here is somethign like it:
http://myspace.com/jenniqu
Ok, so maybe this isin't a 'noob' question. I'm increasing the points :)
-- Jenni
-- The unstated requirement is that a user's friend is not only his/her stated
-- friends, but also anyone who claims the user as a friend.
-- You may need to stop using the * and specify columns, since the UNION
-- requires the same number and type of columns in the results set.
-- Also note that UNION removes dupes by default, which is what you want
SELECT * from Friend A
left JOIN user B ON A.FriendId = B.UserId
LEFT JOIN Image C on B.MainImgId = C.ImageId
WHERE A.UserId = @userid;
UNION
SELECT * from user B
left JOIN Friend A ON A.FriendId = B.UserId
LEFT JOIN Image C on B.MainImgId = C.ImageId
WHERE b.UserId = @userid;
OK, I'm getting some different results now that I plugged it into my stored procedure. I am still getting an unexpected result set. Here is the query after I altered it from your original:
SELECT B.userid,B.username,B.main
A.userId,A.FriendId,A.sort
C.imageSrc,C.ImageText
FROM wisetopic_Friend A
left JOIN wisetopic_user B ON A.FriendId = B.UserId
LEFT JOIN wisetopic_Image C on B.MainImgId = C.ImageId
WHERE A.UserId = @userid
UNION
SELECT B.userid,B.username,B.main
A.userId,A.FriendId,A.sort
C.imageSrc,C.ImageText
FROM wisetopic_User B
left JOIN wisetopic_Friend A ON A.FriendId = B.UserId
LEFT JOIN wisetopic_Image C on B.MainImgId = C.ImageId
WHERE b.UserId = @userid
When I execute the QUERY with the ID of 7 it returns only rows with '7'. I think i have something backwards?? :S
here is the whole friend table results:
userId friendId
----------- -----------
9 7
8 7
(2 row(s) affected)
And the result of the stored proc i changed from your suggestions:
userid username
----------- ---------------
7 ~ Jenni ~
7 ~ Jenni ~
(2 row(s) affected)
Thank you!!!
It looks like you have a data model like this:
wisetopic_User
--------------------
userId
username
...
wisetopic_Friend
--------------------
userId
FriendId
...
It looks like (userID + FriendId) is the unique key for wisetopic_Friend and it looks like userId is the unique key for wisetopic_User. Presumably, both userId and FriendId are foreign keys related to userId in wisetopic_User.
-- So, if you want to pull all of the friends for a specific user, it looks like this:
SELECT
Users.userId [UserID]
, Users.username [User Name]
, Friends.FriendId [FriendID]
, Friend.username [Friend Name]
, FriendPic.imageSrc [Friend SRC]
, FriendPic.ImageText [Friend AltText]
, Friends.sortOrder
, Friends.status
, Friends.dateAdded
, Friends.friendType
FROM
-- Start with all users
wisetopic_User [Users]
-- Join only the desired user to all his/her friends
INNER JOIN wisetopic_Friend [Friends] ON Friends.userId = Users.userId
-- This could be tacked on in the WHERE clause, but narrows the rows faster here
-- It would be *required* to be in the WHERE if we used a LEFT JOIN
And Users.userId = @userid
-- Now get the details (username) for each friend
INNER JOIN wisetopic_User [Friend] ON Friend.userId = Friends.FriendId
-- Get the image of the friends (left join because they may not have a pic ???
LEFT OUTER JOIN wisetopic_Image [FriendPic] ON FriendPic.ImageId = Friend.MainImgId
UNION
--Now, lets get all of the Friends that have selected our @userId as a friend:
SELECT
-- These are switched around from the first example because FriendId is now = @userID
Friends.FriendId [UserID]
, [User].username [User Name]
, Friend.userId [FriendID]
, Friend.username [Friend Name]
, FriendPic.imageSrc [Friend SRC]
, FriendPic.ImageText [Friend AltText]
-- The columns below are of debatable value since they represent the attributes other users stored for our @userID when making him/her a friend
-- You may choose to make these NULL, which is perfectly valid for a UNION
, Friends.sortOrder
, Friends.status
, Friends.dateAdded
, Friends.friendType
FROM
-- Start with all of the Friends
wisetopic_Friend [Friends]
-- Now get the details (username) for our @userID...
INNER JOIN wisetopic_User [User] ON [User].FriendId = Friends.userId
-- that specified our @userId as a friend
And FriendId = @userid
-- Now get the details for the Friends
INNER JOIN wisetopic_User [Friend] ON [Friend].userId = Friends.userId
-- Get the image of the friends (left join because they may not have a pic ???
LEFT OUTER JOIN wisetopic_Image [FriendPic] ON FriendPic.ImageId = Friend.MainImgId
-- *Note, this will not return any rows at all if the @userId has no friends and is not listed by anyone else as a friend
-- *Note, the UNION looks at all of the columns to determine what constitutes a duplicate row
-- The debatable columns above could very well bodge up UNION's ability to get rid of the dupes
-- Another way to go about it would be to collect the last four columns after the UNION has run
-- Let me know if you need an example of doing that with a single statement
Try this:
You may have to list the exact field in the select list.
The distinct will remove duplicates and the b.user_id <> @userid will remove the user
SELECT distinct * from Friend A
left JOIN user B ON B.UserId = A.FriendId
LEFT JOIN Image C on B.MainImgId = C.ImageId
WHERE (A.UserId = @userid OR A.FriendID = @UserID)
AND b.user_id <> @userid
Yes, the AS part is optional, but so are the brackets unless the alias text is a reserved word or has a space or some other character that has a meaning to SQL. It's a style thing. I find that if I format the SQL the same way, I can quickly see what it does. The brackets set off what the aliases are when I quickly scan the code. That's also why I indent the joins if the lower join is related to the join above it. Some of my SQL SELECTs have many joins and it makes them much easier to understand. It also helps to do as you did and only use LEFT JOINs (or only RIGHT JOINS), rather than mixing LEFT and RIGHT joins together in the same statement.
Putting the @userId in the JOIN and not in the WHERE is a debateable improvement. It seems to improve performance, but sacrafices some readability. When dealing with long tables, SQL's optimizer doesn't appear to help out by forcing conditions up higher in the join chain (that logically could be). Ideally, I always want to narrow down the rows as quickly as possible to improve statement performance.
Business Accounts
Answer for Membership
by: Arthur_WoodPosted on 2006-06-01 at 10:04:19ID: 16809109
what fields are you trying to pull, since Select * will select every field from Every Table.
And how do you see this as pulling 'duplicate records'?
AW