I've tried many examples for inner joins, outer joins and even tried conjuring my own with guesses (which more than often works) but no luck here.
TABLE 1:
follower_user_id, followed_user_id
(note it's followeR_ and followeD_)
TABLE 2:
user_id, username
So I need two rows from TABLE 2 where one user_id matches follower_user_id and another row where user_id matches followed_user_id
Query within query works but I know this isn't the way to go...
SELECT f.*, u.*
FROM tbl_follows f, tbl_users u
WHERE follower_user_id = u.user_id
That's the basic query
while($row = $r->fetch_assoc()){
//here i make another query to get the username of the followed_user_id
}
Surely this can be done in a single query?
Thanks in advance
--- UPDATE 1: Sample Data ---
tbl_users
user_id | username
--------------------------------------
1 | abc123
2 | xyz789
3 | nosey123
tbl_follows
follower_user_id | followed_user_id
-------------------------------------------
3 | 2 //nosey123 is following xyz789
3 | 1 //nosey123 is following abc123
1 | 2 //abc123 is following xyz789
While Results :
echo "$row[username] is following $row['???????']<br />"
I'm looking for:
nosey123 is following xyz789
nosey123 is following abc123
abc123 is following xyz789
Have you tried something like this?
SELECT f.*, u.*
FROM tbl_follow f
JOIN tbl_users u ON u.user_id = f.follower_user_id OR u.user_id = f.followed_user_id;
This should return two rows for each userID, since there will be one match for follower user and one match for followed user.
SELECT DISTINCT(A.user_id), A.username, B.*
FROM tbl_follow A
JOIN tbl_users B
ON B.user_id = A.follower_user_id
OR B.user_id = A.followed_user_id;
Related
I have been trying to figure out how to select data related to one id between to tables without limit it to the joined table. I tried using UNION, Inner join, JOIN, but it limit me to show records that are only in both tables. By example:
Table 1 (users)
id | name | register
1 | John | 2014-03-01
2 | Kate | 2014-03-02
etc..
Table 2 (birthdays by example)
id | user | birthday
1 | 1 | 1989-09-09
Note that kate dont have a record on the birthdays table, if i do:
SELECT U.id, name, register, B.birthday FROM users as U INNER JOIN birthday as B ON B.user = U.id
it will only shows JOHN data, i would like to select all my users and if the record do not exist on the joined table, still be able to select all my users, sort of:
id | name | register | birthday
1 | John | 2014-03-01 | 1989-09-09
2 | kate | 2014-03-02 | null or ''
3
4
etc.
Sorry if its a stupid question but i dont find the light on this one. I would appreciate the help.
Regards
You need a LEFT OUTER JOIN instead of the plain JOIN (also known as INNER JOIN), like this:
SELECT U.id, name, register, B.birthday
FROM users as U
LEFT JOIN birthday as B
ON B.user = U.id
A LEFT JOIN between users and birthday tables will contain all records of the "left" table (users), even if the join-condition does not find any matching record in the "right" table (birthday).
This excellent article on The Code Project will help you a lot: Visual Representation of SQL Joins.
Summary of all JOIN types:
Note: Mysql does not support FULL OUTER JOIN but it can be emulated. Useful articles:
https://stackoverflow.com/a/4796911
http://www.sql-tutorial.ru/en/book_full_join_and_mysql.html
http://www.xaprb.com/blog/2006/05/26/how-to-write-full-outer-join-in-mysql/
Use left outer join instead of inner join..
SELECT U.id, name, register, B.birthday
FROM users as U left join birthday as B ON B.user = U.id
I have a query that selects all columns from multiple tables, but it's returning multiples of the same values (I only want distinct values).
How can I incorporate something like this? When I try this, it still
Select Distinct A.*, B.*, C.*....
Does distinct only work when selecting the column names and not all (*) ? In this reference it says distinct in reference to column names, not across all of the tables. Is there any way that I can do this?
edit - I added more info below
Sorry guys, I just got back onto my computer. Also, I just realized that my query itself is the issue, and Distinct has nothing to do with it.
So, the overall goal of my Query is to do the following
Generate a list of friends that a user has
Go through the friends and check their activities (posting, adding friends, etc..)
Display a list of friends and their activities sorted by date (I guess like a facebook wall kind of deal).
Here are my tables
update_id | update | userid | timestamp //updates table
post_id | post | userid | timestamp //posts table
user_1 | user_2 | status | timestamp //friends table
Here is my query
SELECT U.* , P.* ,F.* FROM posts AS P
JOIN updates AS U ON P.userid = U.userid
JOIN friends AS F ON P.userid = F.user_2 or F.user_1
WHERE P.userid IN (
select user_1 from friends where user_2 = '1'
union
select user_2 from friends where user_1 = '1'
union
select userid from org_members where org_id = '1'
union
select org_id from org_members where userid = '1'
)
ORDER BY P.timestamp, U.timestamp, F.timestamp limit 30
The issue I'm having with this (that I thought was related to distinct), is that if values are found to meet the requirements in, say table Friends, a value for the Posts table will appear too. This means when I'm displaying the output of the SQL statement, it appears as if the Posts value is shown multiple times, when the actual values I'm looking for are also displayed
The output will appear something like this (notice difference between post value in the rows)
update_id | update | userid | timestamp | post_id | post | userid | timestamp | user_1 | user_2 | status | timestamp
1 | update1 | 1 | 02/01/2013 | 1 | post1| 1 | 2/02/2013| 1 | 2 | 1 | 01/30/2013
1 | update1 | 1 | 02/01/2013 | 2 | post2| 1 | 2/03/2013| 1 | 2 | 1 | 01/30/2013
So, as you can see, I thought I was having a distinct issue (because update1 appeared both times), but the query actually just selects all the values regardless. I get the results I'm looking for in the Post table, but all the other values are returned. So, when I display the table in PHP/HTML, the Post value will display, but I also get duplicates of the updates (just for this example)
When you select distinct *, you select every row, including the one that makes the record unique. If you want something better than what you are getting, you have to type the individual column names in your select clause.
It would be easy if you explain a little more what is the connection between the tables you'r querying, because you can use joins, unions (as mentioned above) or even group by's ...
Your updated post shows one of the JOIN conditions as:
JOIN friends AS F ON P.userid = F.user_2 OR F.user_1
This is equivalent to:
JOIN friends AS F ON (P.userid = F.user_2 OR F.user_1 != 0)
and will include many rows that you did not intend to include.
You probably intended:
JOIN friends AS F ON (P.userid = F.user_2 OR P.userid = F.user_1)
I think you want this:
select *
from tableA
union
select *
from tableB
union
select *
from tableC
This assumes that HHS tables all have the same number of columns and they are of the same data type. This not, you'll have to select specific columns to make it so.
I have looked through the questions but I cant find anything that does exactly what I need and I can't figure out how to do it myself.
I have 2 tables, a user table and a friend link table. The user table is a table of all my users:
+---------+------------+---------+---------------+
| user_id | first_name | surname | email |
+---------+------------+---------+---------------+
1 joe bloggs joe#test.com
2 bill bloggs bill#test.com
3 john bloggs john#test.com
4 karl bloggs karl#test.com
My friend links table then shows all relationships between the users, for example:
+--------=+---------+-----------+--------+
| link_id | user_id | friend_id | status |
+---------+---------+-----------+--------+
1 1 3 a
2 3 1 a
3 4 3 a
4 3 4 a
5 2 3 a
6 3 2 a
As a note the a in the status column means approved, there could also be r(request) and d(declined).
What I want to do is have a query where if a user does a search it will bring back a list of users that they are currently not already friends with and how many mutual friends each user has with them.
I have managed to get a query for all users that are currently not friends with them. So if the user doing the search had the user id of 1:
SELECT u.user_id,u.first_name,u.surname
FROM users u
LEFT JOIN friend_links fl
ON u.user_id = fl.user_id AND 1 IN (fl.friend_id)
WHERE fl.friend_id IS NULL
AND u.user_id != 1
AND surname LIKE 'bloggs'
How then do I have a count of the number of mutual friends for each returned user?
EDIT:
Just as an edit as I don't think I am being particularly clear with my question.
The query that I currently have above will produce the following set of results:
+---------+------------+---------+
| user_id | first_name | surname |
+---------+------------+---------+
2 bill bloggs
4 karl bloggs
Those are the users matching the surname bloggs that are not currently friends with joe bloggs (user id 1).
Then I want to have how many mutual friends each of these users has with the user doing the search so the returned results would look like:
+---------+------------+---------+--------+
| user_id | first_name | surname | mutual |
+---------+------------+---------+--------+
2 bill bloggs 1
4 karl bloggs 1
Each of these returned users has 1 mutual friend as joe bloggs (user id 1) is friends with john bloggs and john bloggs is friends with both returned users.
I hope this is a bit more clear.
Thanks.
Mutual friends can be found by joining the friend_links table to itself on the friend_id field like so:
SELECT *
FROM friend_links f1 INNER JOIN friend_links f2
ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person1
AND f2.user_id = $person2
But bear in mind that this, in its worst case, is essentially squaring the number of rows in the friend_links table and can pretty easily jack up your server once you have a non-trivial number of rows. A better option would be to use 2 sub-queries for each user and then join the results of those.
SELECT *
FROM (
SELECT *
FROM friend_links
WHERE user_id = $person1
) p1 INNER JOIN (
SELECT *
FROM friend_links
WHERE user_id = $person1
) p2
ON p1.friend_id = p2.friend_id
Also, you can simplify your friend_links table by removing the surrogate key link_id and just making (user_id,friend_id) the primary key since they must be unique anyway.
Edit:
How would this be applied to the original query of searching for users that aren't already friends, I would like to do both in a single query if possible?
SELECT f2.user_id, COUNT(*) 'friends_in_common'
FROM friend_links f1 LEFT JOIN friend_links f2
ON f1.friend_id = f2.friend_id
WHERE f1.user_id = $person
GROUP BY f2.user_id
ORDER BY friends_in_common DESC
LIMIT $number
I am also thinking that the user_id constraints can be moved from the WHERE clause into the JOIN conditions to reduce the size of the data set created by the self-join and preclude the use of subqueries like in my second example.
This query lists anyone who's not friend with user 1 and whose surname matches '%bloggs%':
SELECT
users.user_id,
users.first_name,
users.surname,
Sum(IF(users.user_id = friend_links_1.friend_id, 1, 0)) As mutual
FROM
users inner join
(friend_links INNER JOIN friend_links friend_links_1
ON friend_links.friend_id = friend_links_1.user_id)
ON friend_links.user_id=1 AND users.user_id<>1
WHERE
users.surname LIKE '%bloggs%'
GROUP BY
users.user_id, users.first_name, users.surname
HAVING
Sum(IF(users.user_id = friend_links.friend_id, 1, 0))=0
just change the user id on the ON clause, and the surname on the WHERE clause. I think it should work correctly now!
If A is friend of B, then B is also a friend of A? Wouldn't it be better to use just a link instead of two links (and instead of two rows in friends_links)? Then you have to use two status columns, status1 and status2, and A is friend of B only if status1 = status2 = "a".
There are many ways to show mutual friends, e.g.:
SELECT friend_id
FROM friend_links
WHERE friend_links.user_id = $user1 or friend_links.user_id = $user2
AND NOT (friend_links.friend_id = $user1 or friend_links.friend_id = $user2)
GROUP BY friend_id
HAVING Count(*)>1
And this query shows for each user and anyone who's not his/her friend:
SELECT
users.user_id,
users.first_name,
users_1.user_id,
users_1.first_name
FROM
users INNER JOIN users users_1 ON users.user_id <> users_1.user_id
WHERE
NOT EXISTS (SELECT *
FROM friend_links
WHERE
friend_links.user_id = users.user_id
AND friend_links.friend_id = users_1.user_id)
(The only think I didn't check is the friendship status, but it's easy to add that check).
I'm still working on it, but it's not easy to combine nicely these two queries togheter. So this isn't exactly an answer, I'm just showing some ideas that i've tried.
But what do you need exactly? A query that returns every user with anyone who's not his/her friend and the number of friends in common, or is the user_id already given?
With some code it's not a problem to answer your question... but there has to be a nice way just by using SQL! :)
EDIT:
I'm still wondering if there's a better solution to this, in particular the next query could be extremely slow, but it looks like this might work:
SELECT
users_1.user_id,
users_2.user_id,
Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links_1.friend_id, 1, 0)) As CommonFriend
FROM
users users_1 INNER JOIN users users_2
ON users_1.user_id <> users_2.user_id,
(friend_links INNER JOIN friend_links friend_links_1
ON friend_links.friend_id = friend_links_1.user_id)
GROUP BY
users_1.user_id,
users_2.user_id
HAVING
Sum(IF(users_1.user_id = friend_links.user_id AND users_2.user_id = friend_links.friend_id, 1, 0))=0
(as before, i didn't check friendship status)
If user is given, you could put WHERE users_1.user_id=$user1 but it's better to just leave one user table, and filter the next INNER JOIN whith that user.
Hope you can help me with correct syntax of a SQL query (using MySQL 5.5.25).
I have 3 tables:
data
data_tmp
users
data table is empty - has it's own structure but no rows
data:
id | name | who
----------------
data_tmp:
id | cars | who
---------------
1 | lambo| 2
users
who | name |
------------
2 | john
My query is:
SELECT DISTINCT
users.name,
(SELECT count(id) FROM data WHERE who = 1) as number,
data_tmp.cars
FROM
users, data, data_tmp
WHERE
users.who = 2
AND data_tmp.who = 2
AND data.who = 2
This of course returns an empty result (there is no row that suits to all parameters because data is empty).
What I would like to achieve is:
users.name | number | data_tmp.cars |
-------------------------------------
john | 0 | lambo |
I am sure I have to - in some way - use LEFT JOIN but can't find correct syntax. Hope you can help me.
Kalreg
give this a try (without using subquery)
SELECT a.name, b.cars, count(c.id) as number
FROM users a
INNER JOIN data_tmp b
on a.who = b.who
LEFT JOIN data c
on a.who = c.who AND
a.name = c.name
WHERE a.who = 2
GROUP BY a.name, b.cars
this works on different servers:
MSSQL SERVER # SQLFIDDLE
MYSQL # SQLFIDDLE
Your assumption is right: you have to use left JOIN, in this way :
SELECT DISTINCT users.name, (SELECT count(id) FROM data WHERE who = 1) as number, data_tmp.cars
FROM users
JOIN data_tmp USING (who)
LEFT JOIN data USING(who)
WHERE users.who = 2
table user
id | name | address
3 | Jacko | 33A Herewini
table user_photo
id | userid | thumb | full
1 | 3 | 3k1j_thumb.jpg| 3k1j.jpg
1 | 3 | 3k1j_thumb.jpg| 3k1j.jpg
2 | 14 | 44r_thumb.jpg| 44r.jpg
2 | 14 | 55t_thumb.jpg| 55t.jpg
2 | 14 | 12f_thumb.jpg| 12f.jpg
I got the user id, I want to select his name and address and all his photos
PS: what tool/software you use to draw the table line (the +---+) ?
Edit: then how would you put the name in a div and all the photos in a ul
my html look like this
<div class='name'></div>
...600 elements...
<ul class='photos'></ul>
To get the address, you can just query that table:
SELECT * FROM user WHERE id = 3
To get the photos, you can query the user photo table:
SELECT * FROM user_photo WHERE userid = 3
If you want to get everything at once, you can join the two tables together on the user id:
SELECT * FROM user u
LEFT JOIN user_photo up ON up.userid = u.id
WHERE u.id = 3
Note though that the address info will of course be duplicated on every row
Learn about LEFT JOIN, see e.g. http://www.postgresql.org/docs/8.2/static/sql-select.html
SELECT * FROM user AS u LEFT JOIN user_photo AS p ON p.userid = u.id
Adjust as needed.
To combine the results of two tables linked by one column (id in this case), you would use a JOIN.
You can read up on JOINs in the MySQL Reference Manual
SELECT *
FROM user u
LEFT OUTER JOIN user_photo up ON up.userid = u.id