Join on a cyclic relation (beginner) - mysql

I'm a beginner in queries and I'm struggling with one of them. Here are the two tables involved :
The askstobefriends table permit a user to add a friend in the application I m developping. The relational form of it is :
AskToBeFriends(ID (long), #UserAsker (long), #UserAsked (long), Accept (tinyInt))
So with this table we can see who asked to be friend and if it was accepted ...
The query I m trying to realize would permit to list all the user's friends from his ID and also return the friendship statut (accept field ==> waiting for an answer, accepted or refused).
Speretaly, it would be something like that :
SELECT Accept, UserAsker, UserAsked
FROM askstobefriends
WHERE UserAsker = '".$userID."' OR UserAsked = '".$userID."' ";
==> first issue : it can either be the user who asked to be friend with someone or the opposit, that why i've put and OR. After that, I d like that for everyfriend founded there's these informations :
SELECT colUserID, colUserLogin, colUserName, colUserFirstname
FROM userTable
WHERE colUserID == FRIEND
So I guess I need to do a join query, and in my join I have to be sure that I'm using the right foreign key from the asktobefriends tablefor each cases !! (once the key could be UserAsked and another time UserAsker depending on who asked to be friends :S )
Does anyone have a clue please :S ?? Thanks ;-) !!

Your design is wrong. A User asks to be friend of another User, so "Ask_to_be_friend" is the relation, and the cardinality is many to many, so the design will looks like this:
User_User_ID is UserAsker.
User_USer_ID1 is UserAskedtobefriend
and the query could be like (you'll get all the users that user_user_ID Asks to be friend of):
Select U.* from User as U
Join Ask_to_be_friend as A on
U.user_ID = A.User_user_ID
--where a.accept=1 if you add this, this will give
--you all the friends ID of the user_ID table User
If you want to get the names or extra info of the askedtobefriend you'll need a extra Join
Select U.* from User as U
Join Ask_to_be_friend as A on
U.user_ID = A.User_user_ID
Join User as U2 on
A.User_User_ID1=u2.User_ID
--where a.accept=1 ,with this you'll with get only the friends

You could join the tables using criteria that ensure only friends of :userID are returned. For example:
SELECT u.*, a.Accept
FROM askstobefriends a JOIN userTable u ON (:userID, u.colUserID) IN (
(a.UserAsker, a.UserAsked),
(a.UserAsked, a.UserAsker)
)

Related

2-step SQL Query..something seems wrong

I'm writing what is a pretty simple 2-step SQL Query.
I have one table called Users and another called ProfileCharacteristics.
**Users Table:**
UserId [PK]
UserName
**ProfileCharacteristics Table:**
UserId [FK]
.....(other data)
I'm trying to get access to (other data), but I only have the UserName available. So what I'm presently doing is running one SQL Query that matches the UserName to the UserId and stores the UserId value.
Then, I'm pulling all values that match to UserId in ProfileCharacteristics in a separate query. I have a gut feeling that I could combine these two queries into one, but I'm not sure how.
Any pointers?
EDIT: The start of a JOIN?
SELECT * FROM ProfileCharacteristics
INNER JOIN Users
ON ....
What you're looking for is an INNER JOIN:
SELECT pc.*
FROM ProfileCharacteristics pc
JOIN Users u ON pc.UserId = u.UserId
WHERE U.UserName = 'someuser'
A Visual Explanation of SQL Joins

Joining on the same table more than once

I'm probably being a bit dumb, hopefully someone can help.
I have a simple 2 column user table (ID, USERNAME).
I have a comments table for images (COMMENT, COMMENTFROM, COMMENTTO)
COMMENTFROM is the ID of the user who made the comment. COMMENTTO is the ID of the owner of the image that the comment was added to. Both users are held within the USERS table.
I want to pull out and display rows like this
"really nice photo" - to USERXYZ - from USER123**
This has puzzled me, because if I join the USERS table to the comments table on:
WHERE comments.userfrom = users.id
That only gets me one (or the other) of the 2 usernames I need per row. Is there a way I can get both?
I'm not even sure how I would search for this answer on SOF, apologies if it has been answered before. If anyone can point me in the right direction it would be appreciated :)
You need to JOIN to the users table twice, and give them different identifiers (aka aliases) on each JOIN within your SQL.
SELECT
comment,
userFrom.username AS commentFrom,
userTo.username AS commentTo
FROM comments
JOIN users AS userFrom ON userFrom.ID = comment.commentFrom
JOIN users AS userTo ON userTo.ID = comment.commentTo
Please try following one
SELECT CONCAT(c.comment," - to ",
(SELECT USERNAME FROM user WHERE user.ID = c.COMMENTTO LIMIT 1),
" - from ",
(SELECT USERNAME FROM user WHERE user.ID = c.COMMENTFROM LIMIT 1)) FROM comments c

PHP/MySQL Many to Many. How?

I recently thought that storing an array in MySQL database would solve my problems... then I went and banged my head on a wall until I realised that there was an easier solution to my problem. Unfortunately I can't seem to figure out what the hell I need to do.
I have two tables. User and Entry. Each user can be the Author of any number of entries. One to many right? Well the problem comes from the fact that each entry can have many users. -_-;
As you can imagine, doing this using arrays would be...not only cumbersome but also stupid, especially if someone managed to accumulate 2000 entries. I had anticipated that I might need to create an extra table and some resources do seem to suggest it but the resources aren't as clear as I would have hoped. I will need to get all the users for a post and somewhere else, I'll need to get all the posts for a user.
Can someone explain the best way of doing this? (Without using arrays of course =p)
you need to make 3 tables:
user (primary key = id)
id
name
...
entry (primary key = id)
id
text
...
userentry (primary key = complex key user,entry)
user
entry
if you want to get an entrys users, just do
SELECT
user.*
FROM
userentry
INNER JOIN
user
ON
userentry.user = user.id
WHERE
userentry.entry = [your entry-id]
and to get all entrys of a user, just do it the other way around:
SELECT
entry.*
FROM
userentry
INNER JOIN
entry
ON
userentry.entry = entry.id
WHERE
userentry.user = [your user-id]
The best way to do this is to have three tables:
Users:
Id,
Name,
...
Posts:
Id,
PostName,
...
UserPosts:
Id surrogate key,
UserId,
PostId.
Then to get all the users for a post
SELECT u.*
FROM users u
INNER JOIN posts p ON u.id = p.userid
WHERE p.id = apostid
To get all the posts for a user:
SELECT p.*
FROM posts p
INNER JOIN users u ON u.id = p.userid
WHERE u.id = auserid

Mysql fetching data from multiple tables

I am having three tables
user(id,fname,lname)
picture(picid,pic_path,userid)
friends(friend_of,friends_id,status)
I want to fetch id,fname,lname,pic_path for all friends_id of friends_of=1
picture path may be null
Thankx in advance.
What you're looking for is called a join. In particular, you're looking for a JOIN and a LEFT JOIN.
SELECT
user.id, user.fname, user.lname, picture.pic_path
FROM
friends
JOIN user
ON user.id = friends_id
LEFT JOIN picture
ON userid = user.id
WHERE
friends.friend_of = 1
This will only work though if there's a maximum of 1 entry in picture.
Though this answers your immediate question, I suggest you become very familiar with joins. They're one of the fundamental operations of a relational database. (Note that a join essentially is a mathematical relation)
Try this
SELECT u.*,p.*,f.*
FROM USER u
LEFT JOIN picture p ON p.user_id = id
INNER JOIN friends f ON f.friends_of = u.id
WHERE f.friends_id = 1
For querys like that you need to understand and employ the relations between your entities. Then you work in two steps: selection and projection and contrary to what SQL-syntax may imply the part before the FROM keyword is the projection.
First we compile data. Clearly we need the data from all three tables and we need it once. So at first we construct all possible combinations, by joining all three tables. In SQL this is done in the FROM part, i.e.
FROM friends f, picture p, user u
f, p and u are aliases which serve the purpose of saving us the efford of typing the full table names in the following.
Now we have all possible combinations. Let's select the ones we want:
I suppose every picture in your DB belongs to a user which is stored in your DB as well. So my assumption is that you only want pictures associated to a user. Hence we have a first restrictions on all the combinations we made before! The restriction derived from the (probable) meaning of the data stored in you database and stated as:
u.id = p.userid
(Notice: by applying this restriction to combination above we "select" only certain combinations.)
Then you already stated another restrictions as a request "friends_of=1" to associate this constraint on the combination we write:
f.friends_of=1
Then we combine your request "friends_of=1" with the other data by:
f.friend_of = u.id
This constraint selects only those users who are a friend of somebody. Now we can combine these constraints. As we want all constraints to be satisfied we AND them in a WHERE statement:
WHERE u.id = p.userid AND f.friend_of = u.id AND f.friends_of=1
The ordering does not affect meaning (in this case. But let's rethink those constraints:
u.id = p.userid : we want information about the user and the pictures associated with that user
f.friend_of = u.id : we are looking for a users who are friends of somebody
f.friends_of=1 : we are looking for friends of a particular somebody
Now we project the data stored in our DB to what we want. We want all the user data and picture paths. In SQL:
SELECT u.*,p.pic_path
Now we put everything together.
SELECT u.*,p.pic_path FROM friends f, picture p, user u WHERE u.id = p.userid AND f.friend_of = u.id AND f.friends_of=1
To allow for friends that don't have a picture associated with them (note: that's very different to pic_path being NULL) you need an outer join, which means you also want combinations with empty sets. That's where my MySQL is not so good but I'd guess you'd generate all combinations you want (and many more) with:
FROM friends f JOIN user u LEFT JOIN picture p ON u.id = p.userid
and
SELECT u.*,p.pic_path FROM friends f JOIN user u LEFT JOIN picture p WHERE f.friend_of = u.id AND f.friends_of=1
Notice, that the constraint that may be violated has been made explicit by moving it from the general selection to the generation of the data combinations as a rule on how to create combinations. And yes, it's a shortcut instead of following through the idea of selection and projection.

MYSQL : Problem in writing where clause according to scenario

I have a DB (user_interests) set up with 3 fields: i_id (unique), interest_id, uid.
Then a second DB (interests) set up with the interests: interest_id (unique), interest_name
I'd like to do an SQL query to return a list of interests that two users have in common: User A (owner of a profile) and user B (you/viewer of a profile). I guess I need to query user_interests, then JOIN interests to get the name of the interest.
SELECT user_interests.i_id, user_interests.uid, interests.interest_name
FROM databases.user_interests
LEFT JOIN databases.interests
ON interest.interest_id = user_interest.interest_id
WHERE _______________
I'm confused about the where clause (if that is the correct way to do it at all). My goal is to get the interest_id from user_interests.interests where user_interests.uid is both A and then B (in separate rows).
I saw this link, but couldn't figure out what exactly I was missing: Group by x where y = A and B and C
I would solve it by joining two copies of user_interests, one which is filtered for user A (the profile owner), and one for user B, (the profile viewer).
SELECT *
FROM interests I
INNER JOIN user_interests A ON
A.interest_id = I.interest_id
AND A.user_id = {profile owner}
INNER JOIN user_interests B ON
B.interest_id = I.interest_id
AND B.user_id = {profile viewer}
Alternatively, more along the lines of the snippet you provided, you could complete the where clause with something like...
SELECT * FROM interests
WHERE interest_id in (SELECT interest_id
FROM users
WHERE user_id = A)
AND
interest_id in (SELECT interest_id
FROM user_interests
WHERE user_id = B)
Hope one of those works for you! Let me know if I can clarify
I don't think you need the where clause in this case just remove it and you will get the set of data you are looking for:
SELECT user_interests.i_id, user_interests.uid, interests.interest_name
FROM databases.user_interests
LEFT JOIN databases.interests
ON interest.interest_id = user_interest.interest_id
You may also create a where statement such as the following if you are looking to get a specific result set. I'm not discrediting the answer previously submitted, I am simply trying to help you with the specific WHERE statement you're looking for.
SELECT user_interests.i_id, user_interests.uid, interests.interest_name
FROM databases.user_interests
LEFT JOIN databases.interests
ON interests.interest_id = user_interests.interest_id
WHERE user_interests.uid IN ('A','B');
Please also note, that I changed your ON join to use interests and user_interests, with 's' appended to both, as those are the names of the table. They maintain the same schema name as they are assigned in the database.
Your query is correct remove the where part and run it. It will give you the same output as you need...