SELECT INNNER JOIN from friends and owner's posts - php

I have 3 tables: user_info , friend_match, posts
user_info : account_id | username
friend_match : friendship_id | friend1 (account_id of 1st) | friend2 (account_id of 2nd)
Friend match contains 2 1 and 1 2, 1 3 and 3 1.
posts : post_id | poster_id | post_message | date_posted
How would I get posts from the user's friends and his own ?
I have tried this, but it seems inefficient and I'm having issues with pagination because the users may have posted more or less which throw off the pagination.
SELECT * FROM
(
SELECT p.post_id, p.post_message, UNIX_TIMESTAMP(p.date_posted) as date_posted, u.username FROM posts p
INNER JOIN friend_match fm
ON p.poster_id = fm.friend1
INNER JOIN user_info u
ON u.account_id = p.poster_id
WHERE fm.friend2 = $sessionid
UNION ALL
SELECT p.post_id, p.post_message, UNIX_TIMESTAMP(p.date_posted) as date_posted, u.username FROM posts p
INNER JOIN user_info u
ON u.account_id = p.poster_id
WHERE p.poster_id = $sessionid
)z
ORDER BY post_id DESC LIMIT $page,$limit";
My end result that I'm hoping for contains posts in order from newest to oldest with the friends posts intermingled with sessionholder's posts in a way that's reliably paginable.

Not a full answer, but maybe use a sub-select somehow like this:
SELECT * FROM posts p
inner join user_info u ON u.account_id = p.poster_id
WHERE p.poster_id = $sessionid or p.poster_id IN
(SELECT f.friend1 FROM friend_match f
WHERE f.friend2 = $sessionid)
ORDER BY post_id DESC LIMIT $page, $limit;

Related

MYSQL : select count with union three table

I have three table content information about posts
and each table has Post_id it's foreign_key for Post table
first table = `likes`
second table = `Comment`
and last one = `Visitor`
each Table has some info about users like session or id and etc
i need to create new view table contain post id and the number of visitor , likes , comment
i tried this
SELECT *
from (
select id , count(id) as Comment
from Post left join Comment on id = Post_id
group by id
UNION
select id, count(id) as Visitor
from Post left join Visitor on id = Post_id
group by id
UNION
select id, count(id) as Likes
from Post left join Likes on id = Post_id
group by id
) CountsTable
GROUP BY CountsTable.id
but it didnt work .
i dont know why the result is only the first inner select
in my example the result is
| id | Comment|
|--------|------- |
| 1 | 55 |
| 2 | 25 |
| 3 | 12 |
i expect something like that
| id | Comment | Likes | Visitor |
|--------------|-------|---------|
| 1 | 55 | 100 | 2000 |
No need to use UNION. Count the records for each post in all three tables and Left Join result with Post table
Try something like this
SELECT id,
comments,
vistors,
likes
FROM Post p
LEFT JOIN (SELECT Count(Post_id) comments, Post_id
FROM Comment
GROUP BY Post_id) c
ON p.id = c.Post_id
LEFT JOIN (SELECT Count(Post_id) vistors, Post_id
FROM Visitor
GROUP BY Post_id) v
ON p.id = v.Post_id
LEFT JOIN (SELECT Count(Post_id) likes, Post_id
FROM Likes
GROUP BY Post_id) l
ON p.id = l.Post_id
You can do it with a Left Join query, e.g.:
select u.id, count(distinct l.id) as likes, count(distinct c.id) as comments
from user u left join likes l on u.id = l.user_id
left join comments c on u.id = c.user_id
group by u.id;
Here is SQL Fiddle.
SELECT id, SUM(Comment),SUM(Visitor),SUM(Likes) from (
select id , count(id) as Comment, 0 as Visitor, 0 as Likes
from Post left join Comment on id = Post_id
group by id
UNION ALL
select id, 0 as Comment, count(id) as Visitor , 0 as Likes
from Post left join Visitor on id = Post_id
group by id
UNION ALL
select id, 0 as Comment, 0 as Visitor, count(id) as Likes
from Post left join Likes on id = Post_id
group by id
) CountsTable
GROUP BY CountsTable.id

Slow mysql of a PHP Board

I have multiple tables of a php board.
I need an effective query, to select all categories, all topics, last post of topics, with the posted user. With my query it takes 5-8 seconds to run it.
I did an optimize with last_post_id field into topics table, but I need a better solution for it.
Structure
forum_categories ~ 15 lines
id|name|...
forum_topics ~ 150 lines
id|name|category_id|...
forum_posts ~ 1.000.000 lines
id|body|topic_id|user_id|...
users ~ 30.000 lines
id|username|...
category 1
- topic 1
- last post1 | user1
- topic 2
- last post2 | user2
...
category 2
- topic 3
- last post3 | user3
...
...
Last query (This was a help from my friend. But this also was so slow. )
SELECT c.NAME AS category,
t.NAME AS topic,
p.body AS post,
p.username AS username
FROM forum_categories AS c
JOIN forum_topics AS t
ON t.category_id = c.id
JOIN (SELECT *
FROM (SELECT p.body,
p.topic_id,
u.username
FROM forum_posts AS p
JOIN users AS u
ON u.id = p.user_id
ORDER BY p.id DESC) AS t
GROUP BY topic_id) AS p
ON t.id = p.topic_id
Exaplain query
Statistic of query
Headers are: sort, status, time | status, all time, pct. time, calls, time
I think "last post of topics" is key point of your query. That's why you used ORDER BY on most inner query but this makes two sub-queries.
Updated version
CREATE TEMPORARY TABLE last_post_per_topic_t ENGINE = MEMORY
SELECT topic_id, MAX(id) AS id -----+
FROM forum_posts --> find last post id per topic
GROUP BY topic_id; -----------------+
ALTER TABLE last_post_per_topic_t ADD INDEX (id, topic_id);
SELECT *
FROM forum_categories AS c INNER JOIN forum_topics t ON c.id = t.category_id
INNER JOIN forum_posts p ON p.topic_id = t.id
INNER JOIN last_post_per_topic_t ON last_post_per_topic_t.topic_id = t.id
AND last_post_per_topic_t.id = p.id;
INNER JOIN users u ON p.user_id = u.id;
first version
SELECT *
FROM forum_categories AS c INNER JOIN forum_topics t ON c.id = t.category_id
INNER JOIN forum_posts p ON p.topic_id = t.id
INNER JOIN (
SELECT topic_id, MAX(id) AS id -----+
FROM forum_posts --- find last post_id per topic
GROUP BY topic_id ---------------+
) last_post_per_topic_t ON last_post_per_topic_t.topic_id = t.id
AND last_post_per_topic_t.id = p.id;

which is the best way to order by count from multiple tables?

I'm wondering about these queries and I got a work that want to list all users in table user and count for their post photo and video. and can choose to view in sort by these count limit by ASC or DESC.
I've tried them both but see that sub-query is fast than join. i want to know the different between these queries. Why sometimes join is slower that a sub-query. is join best for only two tables? Is this both best for my work? or you can suggest another better solution.
SUB-QUERY
select
user.*,
(select count(*) from post where post.userid = user.id) postCount,
(select count(*) from photo where photo.userid = user.id) photoCount,
(select count(*) from video where video.userid = user.id) videoCount
from user order by postCOunt desc limit $starrow 20
JOIN
SELECT u.id,
COUNT(DISTINCT p.id) AS postCount,
COUNT(DISTINCT ph.id) AS photoCount,
COUNT(DISTINCT v.id) AS videoCount
FROM user u
LEFT JOIN post p
ON p.userid = u.id
LEFT JOIN photo ph
ON ph.userid = u.id
LEFT JOIN video v
ON v.userid = u.id
GROUP BY u.id
ORDER BY postCount LIMIT $startrow 20
Example in HTML page that order by postCount DESC and have paging.
userid postCount photoCount videCount
1 34 5 4
2 30 12 2
3 21 5 6
4 15 8 4
5 12 15 9
6 8 3 10
.. .. .. ..
You can try it this way with JOIN
SELECT u.id, postCount, photoCount, videoCount
FROM user u LEFT JOIN
(
SELECT userid, COUNT(*) postCount
FROM post
GROUP BY userid
) p ON p.userid = u.id LEFT JOIN
(
SELECT userid, COUNT(*) photoCount
FROM photo
GROUP BY userid
) ph ON ph.userid = u.id LEFT JOIN
(
SELECT userid, COUNT(*) videoCount
FROM video
GROUP BY userid
) v ON v.userid = u.id
ORDER BY postCount
LIMIT $startrow, 20

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;

Get random friends from mysql

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

Categories