Counting all and selecting single row from joined table - mysql

I have the following tables: users, posts, and likes
I want to receive a total count of 'likes' for that post but also the id of the like if it exists.
Do I need the 2 JOINS for the same table? Or is there a more efficient way
SELECT p.id, u.username, p.message, count(DISTINCT l.id) AS likeCount, l2.id AS likedID
FROM posts p
INNER JOIN users u ON p.userID = u.id
LEFT JOIN likes l ON p.id = l.postID
LEFT JOIN likes l2 ON l2.userID = ? AND l2.postID = p.id
WHERE p.status = 0

Related

Mysql query returning too many results

I'm working on a project where I need to check if the user liked the post and then use COUNT() on it, if it gives 0 they haven't if it says 1 they have liked it
I tried using this query
SELECT P.id AS id
, U.username AS username
, P.body AS body
, P.timestamp AS timestamp
, COUNT(L.user_id) AS likes
, COUNT(LD.post_id) AS liked
FROM posts AS P
LEFT JOIN users AS U ON U.id = P.user_id
LEFT JOIN followers AS F ON F.user_id = 'user1'
LEFT JOIN likes AS L ON L.post_id = P.id
LEFT JOIN likes AS LD ON LD.post_id = P.id
AND LD.user_id = 'user1'
WHERE F.following_id = P.user_id
OR P.user_id = 'user1'
GROUP BY P.id
My entrys in my likes table are
UserId|PostId|timestamp
user1 |post1 |time
user2 |post1 |time
My problem is it keeps giving a 2 for the count of LD which shouldn't be possible
*Note: In my code I use :user through PDO I don't actually type the id like that
Edit:
$sql = "SELECT P.id AS id, P.user_id AS userid, U.username AS username, U.name AS name, U.verified AS verified, P.body AS body, P.data AS data, P.timestamp AS timestamp, P.type AS type, P.users AS users, COUNT(L.user_id) AS likes, COUNT(DISTINCT LD.post_id) AS liked FROM posts AS P LEFT JOIN users AS U ON U.id = P.user_id LEFT JOIN followers AS F ON F.user_id = :userid LEFT JOIN likes AS L ON L.post_id = P.id LEFT JOIN likes AS LD ON LD.post_id = P.id AND LD.user_id = :userid WHERE F.following_id = P.user_id OR P.user_id = :userid GROUP BY P.id";
$results = DB::query($sql, array(':userid' => $user_id));
I then loop through the results and format them into json
Can you try adding a DISTINCT keyword on the COUNT function for liked column?
COUNT(DISTINCT LD.post_id) AS liked
Most likely the joins are causing the likes table to be duplicated. Thus, we'll only count the unique posts (by post_id) using DISTINCT.

join 3 sql tables and make nested query

So I have 3 tables called comments, users and posts.
I want to get
the "score" from comments
the "user reputation" for users by doing the left join between comments and users with c.user_id = u.id
get the "tags" from posts table by doing a left join between comments and posts on c.post_id = p.id.
BUT there is a trick here the tags should be based on the type of the posts (p.post_type_id).
So if the id = 1 then that means we have a "question" as a post and simply retrieve tag
Else if the id = 2 then that means we have an answer and to get the tag we have to look at its parent_id from posts table.
I tried to use WHERE, CASE, nested IF, and nested SELECT but all threw syntax errors
Finally, I tried to do the following but I got an empty result
SELECT c.score,
COALESCE (u.reputation) reputation,
COALESCE (p.tags) tags
FROM comments c
LEFT JOIN users u
ON c.user_id = u.id
LEFT JOIN posts p
ON (c.post_id = p.id AND p.post_type_id = 1) OR (c.post_id = p.id AND p.post_type_id = 2 )
WHERE (p.id = p.parent_id)
So how can I have the tags based on the two types ?
Just quick guess:
http://sqlfiddle.com/#!9/a1cc3/1
SELECT c.score,
u.reputation reputation,
IF(p.post_type_id=1,p.tags,
IF(p.post_type_id=2,parents.tags,'UNKNOWN POST TYPE')
) tags
FROM comments c
LEFT JOIN users u
ON c.user_id = u.id
LEFT JOIN posts p
ON c.post_id = p.id
LEFT JOIN posts parents
ON parents.id = p.parent_id
UPDATE Here is Postgres variant:
http://sqlfiddle.com/#!15/a1cc3/2
SELECT c.score,
u.reputation,
CASE p.post_type_id
WHEN 1 THEN p.tags
WHEN 2 THEN parents.tags
ELSE 'UNKNOWN POST TYPE'
END tags
FROM comments c
LEFT JOIN users u
ON c.user_id = u.id
LEFT JOIN posts p
ON c.post_id = p.id
LEFT JOIN posts parents
ON parents.id = p.parent_id

mysql join with multiple tables and count query

I have total 6 tables in which different info has been saved
Now i need a result in which get count from 5 tables and select all info from main table but if record does not exist than it must be need to return 0 instead of no row found that's the problem here
I have tried below query but didn't get success
SELECT
u.*,
COUNT(DISTINCT c.id) as comments,
COUNT(DISTINCT d.id) as dislikes,
COUNT(DISTINCT l.id) as likes,
COUNT(DISTINCT s.id) as shares,
COUNT(DISTINCT t.id) as tags
FROM
job_details as u
JOIN job_comments as c ON u.id = c.job_id
JOIN job_dislike as d ON u.id = d.job_id
JOIN job_like as l ON u.id = l.job_id
JOIN job_share as s ON u.id = s.job_id
JOIN job_tags as t ON u.id = t.job_id
WHERE
u.id = c.job_id AND
u.id = d.job_id AND
u.id = l.job_id AND
u.id = s.job_id AND
u.id = t.job_id
GROUP BY
u.id
This query is executed, but didn't get exact result.
I don't quite understand why.
I was hoping somebody here could help me out?
Thanks!
You probably didn't get the exact result because some tables may be missing values.
Although you can solve this problem with a LEFT JOIN, the safer solution is to pre-aggregate the data:
SELECT u.*, c.comments, d.dislikes, l.likes, s.shares, t.tags
FROM job_details as u LEFT JOIN
(select c.job_id, count(*) as comments from job_comments group by c.job_id
) c
ON u.id = c.job_id LEFT JOIN
(select d.job_id, count(*) as dislikes from job_dislike d group by d.job_id
) d
ON u.id = d.job_id LEFT JOIN
(select l.job_id, count(*) as likes from job_like l group by l.job_id
) l
ON u.id = l.job_id LEFT JOIN
(select s.job_id, count(*) as shares from job_share s group by s.job_id
) s
ON u.id = s.job_id LEFT JOIN
(select t.job_id, count(*) as tags from job_tags t group by t.job_id
) t
ON u.id = t.job_id;
Why is this better? Consider an id that has 5 comments, likes, dislikes, shares and tags. The JOIN approach produces an intermediate result with 5*5*5*5*5 = 3,125 intermediate rows. Things can really get out of hand for popular ids.
Use LEFT JOIN instead of JOIN. and you don't need WHERE clause since you have joined those tables. And, use IFNULL function to return 0 for null values. You need to modify you query like this :
SELECT u.id,
IFNULL(COUNT(DISTINCT c.id),0) as comments,
IFNULL(COUNT(DISTINCT d.id),0) as dislikes,
IFNULL(COUNT(DISTINCT l.id),0) as likes,
IFNULL(COUNT(DISTINCT s.id),0) as shares,
IFNULL(COUNT(DISTINCT t.id),0) as tags
FROM job_details as u
LEFT JOIN job_comments as c ON u.id = c.job_id
LEFT JOIN job_dislike as d ON u.id = d.job_id
LEFT JOIN job_like as l ON u.id = l.job_id
LEFT JOIN job_share as s ON u.id = s.job_id
LEFT JOIN job_tags as t ON u.id = t.job_id
GROUP BY u.id

MySql join with 2 Tables and 2 join

I have 2 tables:
posts: userid, lastuserid
users: id, name
I need to join posts.userid = users.id and posts.lastuserid = users.id to get username and lastusername.
My query did as below:
SELECT posts. * , users.name, vUsers.name
FROM posts
INNER JOIN users ON users.id = posts.userid
INNER JOIN Users ON vUsers.id = posts.lastuserid
Is there any other (better) way to do this?
Your query is probably correct. I would encourage you to use table aliases that are abbreviations for the things you are looking for:
SELECT p. * , u.name as username, l.name as lastusername
FROM posts p INNER JOIN
users u
ON u.id = p.userid INNER JOIN
users l
ON l.id = p.lastuserid;
Your query has something called vUsers, which is not defined.

Mysql query help. I need to make sure atleast one record is returning

I have a query that I know it should atleast return one row. How can i modify my follow query to make sure that album returns data. thanks for any help.
Query Here. I know that Album has a row and I need to return it.
select distinct p.*,
a.ID as parentalbumid,a.CreatorID as albumcreatorid,a.AlbumName,a.AlbumDescription,a.AlbumDefaultImageURL,a.Private,a.DateCreated,a.AdultContent,a.PasswordProtected,a.AllowTags,a.TypeID,a.AlbumAutoID,
mainuser.Username as mainuserusername,mainuser.ID as mainuserid,mainuser.PictureUrl as mainuserpictureurl,
c.ID as commentID,c.PhotoID as commentphotoid,c.OutputMessage,c.CommentDate,
t.ID as tagID,t.PhotoID as tagphotoid,t.UserID,t.TextTag,t.LeftLocation,t.TopLocation,
u.ID as userid,u.Username,u.FirstName,u.LastName,u.PictureUrl
from photos p
inner join albums a on a.ID = p.AlbumID
inner join users mainuser on mainuser.ID = p.UserID
left join comments c on c.PhotoID = p.ID
left join tags t on t.PhotoID = p.ID
left join users u on u.ID = c.CommentBy
where a.AlbumAutoID = 3
order by p.DateUploaded desc;
Use only LEFT JOINs (and put the table albums as the first table of your FROM):
select distinct p.*,
a.ID as parentalbumid,a.CreatorID as albumcreatorid,a.AlbumName,a.AlbumDescription,a.AlbumDefaultImageURL,a.Private,a.DateCreated,a.AdultContent,a.PasswordProtected,a.AllowTags,a.TypeID,a.AlbumAutoID,
mainuser.Username as mainuserusername,mainuser.ID as mainuserid,mainuser.PictureUrl as mainuserpictureurl,
c.ID as commentID,c.PhotoID as commentphotoid,c.OutputMessage,c.CommentDate,
t.ID as tagID,t.PhotoID as tagphotoid,t.UserID,t.TextTag,t.LeftLocation,t.TopLocation,
u.ID as userid,u.Username,u.FirstName,u.LastName,u.PictureUrl
from albums a
left join photos p on a.ID = p.AlbumID
left join users mainuser on mainuser.ID = p.UserID
left join comments c on c.PhotoID = p.ID
left join tags t on t.PhotoID = p.ID
left join users u on u.ID = c.CommentBy
where a.AlbumAutoID = 3
order by p.DateUploaded desc;