Get random friends from mysql - php

There where 2 mysql tables users(id,name,city) and friend_list(id,userid,friend,status).
Now i need to get three random friends from the friend_list table and their name from users table.
Friend_list table
id | userid |friend |status
1 | 1 | 2 | friends
2 | 3 | 1 | friends
3 | 2 | 3 | friends
users table:
id | name
1 | xxx
2 | yyy
3 | zzz
I need query something like this.
SELECT f.*,u.name FROM friend_list f,users u WHERE (f.userid = 1 or f.friend = 1) AND f.status = 'friends' AND f.userid = u.id AND f.order by RAND() limit 3
but for eg: it should select 1 in userid column and also from friend column.
I m trying to achieve it without using JOIN's

You can use the oreder by rand() as in below query.
select Friend_list.friend,users.name from Friend_list inner join users on Friend_list.userid=users.id order by rand();

To select 2 random entries try:
SELECT * FROM
(
SELECT * from users join on Friend_list.userid = users.id where users.id = ?
) as sub_equity
ORDER BY RAND() LIMIT 2
I had a same task on a project :-)

SELECT Friend_list.*, users.name
FROM Friend_list INNER JOIN users ON Friend_list.userid = users.id
ORDER BY RAND() // this will show random records

You can use ORDER BY RAND() LIMIT 3;

Try this:
SELECT * FROM friend_list f
INNER JOIN users u ON u.id = f.userid
ORDER BY rand() LIMIT 1;
SQL FIDDLE: http://sqlfiddle.com/#!2/e483c/1/0

ORDER BY RAND() is quite slow if there are many rows.
If users.id is sequential and you have statistic on users.id (e.g. MAX(users.id), MIN(users.id)), generate three random number between min, max in client side.
And following query:
SELECT u.name as person, u2.name as friend_with
FROM users u
INNER JOIN friends_list f ON u.id = f.userid
WHERE users.id IN (random_number1, 2, 3);
this query can use INDEX, so it's faster than ORDER BY RAND()
ah.. users.id would not be continuous (e.g user deleted), so you need to generate enough random number.

Try doing this:
SELECT u.name as person, u2.name as friend_with
FROM users u
INNER JOIN friends_list f ON u.id = f.userid
INNER JOIN users u2 ON u2.id = f.friend
WHERE f.userid = 1 or f.friend = 1
AND f.status = 'friends'
ORDER BY rand() LIMIT 3;
SQLFIDDLE DEMO
This will get you three random records with the name of the person and the name of his friend, being one of the userid 1

Related

mysql multiple COUNT() from multiple tables with LEFT JOIN

I want to show the conclusion of all users.
I have 3 tables.
table post
post_id(index) user_id
1 1
2 3
3 3
4 4
table photo
photo_id(index) user_id
1 2
2 4
3 1
4 1
table video
photo_id(index) user_id
1 4
2 4
3 3
4 3
and in table user
user_id(index) user_name
1 mark
2 tommy
3 john
4 james
in fact, it has more than 4 rows for every tables.
I want the result like this.
id name post photo videos
1 mark 1 2 0
2 tommy 0 1 0
3 john 2 0 2
4 james 1 1 2
5 .. .. .. ..
Code below is SQL that can work correctly but very slow, I will be true appreciated if you help me how it using LEFT JOIN for it. Thanks.
SQL
"select user.*,
(select count(*) from post where post.userid = user.userid) postCount,
(select count(*) from photo where photo.userid = user.userid) photoCount,
(select count(*) from video where video .userid = user.userid) videoCount
from user order by user.id"
(or ORDER BY postCount, photoCount or videoCount ASC or DESC as i want )
I done researched before but no any helped me.
SELECT u.user_id,
u.user_name,
COUNT(DISTINCT p.post_id) AS `postCount`,
COUNT(DISTINCT ph.photo_id) AS `photoCount`,
COUNT(DISTINCT v.video_id) AS `videoCount`
FROM user u
LEFT JOIN post p
ON p.user_id = u.user_id
LEFT JOIN photo ph
ON ph.user_id = u.user_id
LEFT JOIN video v
ON v.user_id = u.user_id
GROUP BY u.user_id
ORDER BY postCount;
Live DEMO
Your method of doing this is quite reasonable. Here is your query:
select user.*,
(select count(*) from post where post.userid = user.userid) as postCount,
(select count(*) from photo where photo.userid = user.userid) as photoCount,
(select count(*) from video where video.userid = user.userid) as videoCount
from user
order by user.id;
For this query, you want the following indexes:
post(userid)
photo(userid)
video(userid)
user(id)
You probably already have the last one, because user.id is probably the primary key of the table.
Note that a left join approach is a bad idea in this case. The three tables -- posts, photos, and videos -- are independent of each other. If a user has five of each, then joining them together would produce 125 intermediate rows. If a user has fifty of each, it would be 125,000 -- a lot of extra processing.
Your answer is probably slow as it is using a correlated sub-query i.e. the sub query is running once for each user_id (unless the optimizer is doing something smart - which shouldn't be counted on).
You could use a left outer join and count or use something temporary like:
SELECT u.user_id,
u.user_name,
ph.user_count AS 'photoCount',
p.user_count AS 'postCount',
v.user_count AS 'videoCount'
FROM user u
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM photo
GROUP BY user_id
) ph
ON ph.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM post
GROUP BY user_id
) p
ON p.user_id=u.user_id
INNER JOIN ( SELECT user_id,
COUNT(*) AS user_count
FROM video
GROUP BY user_id
) v
ON v.user_id=u.user_id
There are pros and cons for both (depending on indexes). Always have a look at the query plan (using EXPLAIN for MySQL).

Slow query using "where in" and "order by select count"

I want to show post from users that specified user is followed and i have two tables at below. but its query is very slow.
table user
id | username
1 | name1
2 | name2
3 | name3
..
..
table post
id | poster_id | post_content
1 | 2
2 | 3
3 | 10
..
..
table follow
followerid | followtoid
1 | 2
1 | 3
2 | 10
..
..
Assume that all tables have more than 1000 rows.
This's SQL
SELECT *
FROM post
WHERE poster_id IN (
SELECT followtoid
WHERE followerid = $_SESSION['userid']
)
And this's the second cast is very slow too.
I want to list all member by order from their total posts.
SELECT *
FROM user
ORDER BY (
SELECT COUNT(id)
FROM post
WHERE post_id = user.id
) DESC;
Try indexing post.userid, post.poster_id, followtoid.followerid and user.user_id, using CREATE INDEX, and use LEFT JOIN clause on your queries instead:
SELECT *
FROM user u
LEFT JOIN SELECT poster_id, COUNT(*) as count FROM post p GROUP BY poster_id
ON (u.user_id = p.poster_id)
ORDER BY count DESC;
and:
SELECT * FROM post AS p
LEFT JOIN (SELECT followerid FROM followtoid) AS f
ON (p.userid=f.followerid)
WHERE p.userid = {$_SESSION['userid']}
Use a JOIN for the first query
SELECT p.*
FROM post p
JOIN follow f ON p.post_id = f.followtoid
WHERE f.followerid = $_SESSION['userid']
and a JOIN plus a GROUP BY for the second
SELECT u.*, tbl.postCount
FROM user u
JOIN (
SELECT poster_id, COUNT(*) AS postCount
FROM post p
GROUP BY posterID
) tbl ON tbl.poster_id = u.id
ORDER BY postCount DESC
You can accomplish the second query without a subquery:
SELECT u.*, COUNT(p.poster_id) as postCount
FROM user u
LEFT JOIN post p
ON (u.user_id = p.poster_id)
GROUP BY u.user_id
ORDER BY postCount DESC;

MySql query, counting occurrences of user_id

My query is:
SELECT * FROM (SELECT user_id
FROM goals
LEFT JOIN goal_results ON goals.id = goal_results.goal_id
WHERE goals.enabled = 1 AND validation = 'accepted') AS u
My results are:
| user_id |
| 4 |
| 5 |
| 4 |
| 5 |
| 6 |
I need to get the count of each of them like:
4 > 2
5 > 2
6 > 1
I've tried many kind of queries with subqueries or using distinct but I'm lost and I don't reach my goal.
You can achieve this by using GROUP BY and COUNT. The subquery is not needed.
SELECT goal_results.user_id, COUNT(*) qty
FROM goals
LEFT JOIN goal_results ON goals.id = goal_results.goal_id
WHERE goals.enabled = 1 AND goal_results.validation = 'accepted'
GROUP BY goal_results.user_id
Adding group by will do.
SELECT u.user_id, count(*) FROM (SELECT user_id
FROM goals
LEFT JOIN goal_results ON goals.id = goal_results.goal_id
WHERE goals.enabled = 1 AND validation = 'accepted') AS u
group by u.user_id
You don't need to do this with a subquery:
SELECT g.user_id, count(*)
FROM goals g LEFT JOIN
goal_results gr
ON g.id = gr.goal_id
WHERE g.enabled = 1 AND validation = 'accepted'
GROUP BY g.user_id;
My guess, though, is that you really want:
SELECT g.user_id, count(gr.goal_id)
FROM goals g LEFT JOIN
goal_results gr
ON g.id = gr.goal_id
WHERE g.enabled = 1 AND validation = 'accepted'
GROUP BY g.user_id;
This will return 0 for users that have no goals. The first will return 1 for them.

MySQL Query - a bit tricky

i'm having the following tables:
USERS: ITEMS
user_id name always_show id user_id name
-------------------------- --------------------------------
1 Joe 1 1 Apple
2 Sam 2 1 Banana
3 Walter 1 3 2 Cherry
i'm doing this query:
SELECT * FROM
users Inner Join
items On users.user_id = items.user_id
The question is: how can i add all other users which have the flag always_show set?
i hope i understand your question :-) try UNION
SELECT u.* FROM users u
INNER JOIN items i ON u.user_id = i.user_id
UNION ALL SELECT * FROM users WHERE always_show = 1
SELECT * FROM
users Inner Join
items On users.user_id = items.user_id where Users.always_set = 1
SELECT *
FROM users
INNER JOIN items On users.user_id = items.user_id
UNION
SELECT *
FROM users
LEFT OUTER JOIN items On users.user_id = items.user_id AND users.always_show = 1

mysql query within a query with privacy condition check

I have 3 tables.
myMembers
------------------------------------
id | username | privacy
------------------------------------
1 | userA | 0
2 | userB | 1
3 | userC | 0
4 | userD | 1
following
--------------------------------
id | user_id | follower_id
--------------------------------
1 | 2 | 1
posts
-------------------------------------
id | userID | username | statusMsg
--------------------------------------
1 | 4 | userD | Issac Newton is genius
2 | 2 | userB | Newton Saw apple
3 | 3 | userC | Newtonian Physics
4 | 1 | userA | Calculus came from Sir Newton
There is a search field. When a logged in user searches for 'keyword' in table 'posts', I want to omit results from those users who has set his privacy to '1' and WHERE searcher is not following user B.
The query should logically do this.
SELECT * from posts WHERE (match the keyword)
AND (
if (poster's privacy (which is set in myMembers)==1){
if (seacher is following poster){
select this post
}
}
else { select this post
}
)
LIMIT results to 5 rows
So for a keyword "Newton",
if userA is searching, rows 2,3,4 from 'posts' should be returned.
if userD is searching, only rows 1, 3 and 4 from 'posts' should be returned,
based on privacy and following
Edit: Tagging for future searches: IF condition within WHERE Clause in mySql
Please, try this query (also on SQL Fiddle):
SELECT p.id, p.user_id, m.username, m.privacy,
searcher.username "Searcher", p.status_msg
FROM posts p
JOIN members m ON m.id = p.user_id
LEFT JOIN following f ON p.user_id = f.user_id
JOIN members searcher ON searcher.username = 'userA'
WHERE (m.privacy = 0 OR (m.privacy = 1 AND f.follower_id = searcher.id)
OR m.id = searcher.id)
AND p.status_msg LIKE '%New%'
ORDER BY p.id
LIMIT 5;
I removed username field from posts table, as it is redundant. Also, I named tables and columns slightly different, so query might need cosmetic changes for your schema.
The first line in the WHERE clause is the one that you're looking for, it selects posts in the following order:
First posts from members without privacy;
Then posts from members that are followed by the current searcher;
Finally, posts of the member himself.
EDIT:
This query is using original identifiers:
SELECT p.id, p.`userID`, m.username, m.privacy,
searcher.username "Searcher", p.`statusMsg`
FROM posts p
JOIN `myMembers` m ON m.id = p.`userID`
LEFT JOIN following f ON p.`userID` = f.user_id
JOIN `myMembers` searcher ON searcher.username = 'userD'
WHERE (m.privacy = 0 OR f.follower_id = searcher.id OR m.id = searcher.id)
AND p.`statusMsg` LIKE '%New%'
ORDER BY p.id
LIMIT 5;
EDIT 2:
To avoid duplicates in case there're several followers for the user from the posts table, join and filtering conditions should be changed the following way (on SQL Fiddle):
SELECT p.id, p.user_id, m.username, m.privacy,
searcher.username "Searcher", p.status_msg
FROM posts p
JOIN members m ON m.id = p.user_id
JOIN members searcher ON searcher.username = 'userC'
LEFT JOIN following f ON p.user_id = f.user_id
AND follower_id = searcher.id
WHERE (m.privacy = 0 OR (m.privacy = 1 AND f.id IS NOT NULL)
OR m.id = searcher.id)
ORDER BY p.id
LIMIT 5;
Try the following:
SET #my_user_id= 1;
SELECT * FROM posts p
INNER JOIN myMembers m ON p.user_id= m.id
WHERE statusMsg LIKE '%'
AND privacy=0
AND user_id IN (SELECT follower_id FROM following f WHERE f.user_id=#my_user_id)
LIMIT 5
try this:
SELECT a.*
FROM posts a
LEFT JOIN (SELECT user_id
FROM following a1
INNER JOIN myMembers b1
ON a1.follower_id = b1.id
WHERE a1.follower_id = 1 AND
b1.privacy = 1
) b
ON a.userID = b.user_id AND
WHERE a.statusMsg LIKE '%search%' AND
b.user_id IS NULL
LIMIT 5;
or better approach without subquery:
SELECT a.*
FROM posts a
LEFT JOIN myMembers b
ON a.userID = b.id AND
b.privacy = 1
LEFT JOIN following c
ON a.userID = c.user_id AND
c.follower_id = 1
WHERE a.statusMsg LIKE '%search%' AND
b.id IS NULL AND
c.user_id IS NULL
LIMIT 5;
See: A Visual Explanation of SQL Joins

Categories