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
Related
I have table 1: users
id | name |
1 | john |
2 | garry|
3 | sam |
And table two called posts:
id | user_id | title | posted
1 | 1 | Something | 1551128761
2 | 1 | Else | 1551128761
3 | 3 | Some Title | 1551122745
4 | 2 | Demo Title | 1551129777
5 | 3 | Something | 1551126793
user_id in the second table is the id of the user in the first table
I need to get the latest post out of the table and i'm doing that currently by using this query:
SELECT u.id, u.name, p.title
FROM users AS u
LEFT JOIN posts AS p
ON p.user_id= u.id
WHERE p.posted = ( SELECT MAX(posted) FROM posts WHERE user_id = u.id )
ORDER BY u.id
LIMIT 15
But the problem with this query is that if the timestamp is the same for the same user (in this example for user with user_id 1 the timestamp is the same) i'm getting both of those rows instead of just the latest one(the latest one has the highest id)
Try this MySQL query:
SELECT u.id,
u.name,
p.title
FROM users AS u
JOIN posts AS p
ON p.id = (SELECT pi.id
FROM posts AS pi
WHERE pi.user_id = u.id
ORDER BY pi.id DESC
LIMIT 1);
Tested and works fine. Here is a demo: DBFiddle
To speed up select query, consider adding indexes
ALTER TABLE posts ADD INDEX(user_id);
ALTER TABLE posts ADD INDEX(posted);
One option using id column from posts table as following. This is assuming id is going to be different for each post record is posts table. Demo here
SELECT u.id, u.name, p.title,p.posted
FROM users AS u
LEFT JOIN posts AS p
ON p.user_id= u.id
WHERE (p.posted,p.id) = ( SELECT MAX(posted),MAX(id) FROM posts WHERE user_id = u.id )
ORDER BY u.id
How about restructuring the query slightly?
SELECT posts.title, users.id, users.name
FROM posts, users
WHERE posts.user_id = users.id
ORDER BY posts.posted DESC, posts.id DESC
LIMIT 1
Essentially selecting from posts, ordering by the posted timestamp and secondly the id of the post in descending order in case timestamp is the same.
I've two tables, for example:
post:
id | author | content | date
1 | Lucas | Hello! | 2016
2 | Igor | Hi! | 2016
comment:
id | post_id | content | date
1 | 2 | hehehe | 2016
2 | 1 | hahaha | 2016
3 | 2 | huhuhu | 2016
And I to do a SELECT that return all posts and a COUNT of rows of all comments with post.id = comment.id.
So, I tried:
SELECT p.id, p.author, p.content, p.date, COUNT(*) AS numComments FROM post p LEFT JOIN comment ON p.id = post_id WHERE p.author = '$author' GROUP BY p.id DESC LIMIT 12
And I got do it. But, even when no exists comments with p.id = post_id he returns 1.
So, I tried:
SELECT p.id, p.author, p.content, p.date, CASE WHEN COUNT(*) < 1 THEN '0' ELSE COUNT(*) END AS numComments FROM post p LEFT JOIN comment ON p.id = post_id WHERE p.author = '$author' GROUP BY p.id DESC LIMIT 12
But the result is the same. How to do this?
As outer joins return a row even if there's no matching data you need to count a column from the inner table, usually it's the column used in join:
SELECT p.id, p.author, p.content, p.date, COUNT(post_id) AS numComments
FROM post p LEFT JOIN comment ON p.id = post_id
WHERE p.author = '$author'
GROUP BY p.id -- seems to be mysql, otherwise you need to add more columns to the list
If you don't want to show rows with a zero count simply switch to an
INNER JOIN.
you can get count by this way, also last is order by not group by:
SELECT p.id, p.author, p.content, p.date,
(select COUNT(*) from comment where p.id = comment.post_id) AS numComments FROM post p
WHERE p.author = '$author'
ORDER BY p.id DESC LIMIT 12
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;
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;
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