MySQL case when using JOIN/GROUP BY - mysql

I have a posts table. I am joining it with votes table via:
SELECT posts.*,
(CASE
WHEN vs.user_id = 1 THEN 0
ELSE 1
END) AS voted_by_me
FROM `posts`
LEFT OUTER JOIN votes AS vs ON vs.post_id = posts.id
GROUP BY posts.id
Basically I want know if the joined value vs.user_id = 1. This obviously doesn't work because it will just use a random returned value in CASE WHEN condition . I am wondering if there's a way to find out if the join values group by contains a specific value.
To clarify:
I want to get all posts, and also for each post have a column called voted_by_me where if posts was voted by user with id 1, then make it value 0, otherwise 1.

Is that what you want?
SELECT posts.id,
sum(vs.user_id = 1 AND vs.option = 0) > 0 AS downvoted_by_me,
sum(vs.user_id = 1 AND vs.option = 1) > 0 AS upvoted_by_me
FROM `posts`
LEFT OUTER JOIN votes AS vs ON vs.post_id = posts.id
GROUP BY posts.id

SELECT posts.id,
ifnull(vs.isvoted, 0) AS voted_by_me
FROM `posts`
LEFT OUTER JOIN (select distinct postid , 1 as isvoted from votes where user_id=1) AS vs
ON vs.post_id = posts.id

Related

SQL Join gives wrong results (creates duplicates)

I have a problem with my SQL join query. I have looked up other suggested answers and tried to apply it to my query, but it doesn't seem to be working.
I have this query:
SELECT SUM(p.quantity)
FROM stocktake_scans p
LEFT JOIN (
SELECT stocktake_area_id
FROM stocktake_areas
WHERE stocktake_id =8592 AND area_checked = 1
)d ON d.stocktake_area_id = p.stocktake_area_id
LEFT JOIN (
SELECT user_id
FROM stocktake_scan_edit
WHERE user_id =46521
)e ON e.user_id = p.stocktake_staff_id
WHERE p.stocktake_staff_id = 46521
And it gives me a result of 42, while I should get only 6. What is missing from the query?
I think you may have extra records with the same ID in your joined table that is where you are getting multiple rows returned from which is then calculating wrong in your sum, please try the below.
SELECT SUM(p.quantity) FROM stocktake_scans p LEFT JOIN ( SELECT distinct stocktake_area_id FROM stocktake_areas WHERE stocktake_id =8592 AND area_checked = 1 )d ON d.stocktake_area_id = p.stocktake_area_id LEFT JOIN ( SELECT distinct user_id FROM stocktake_scan_edit WHERE user_id =46521 )e ON e.user_id = p.stocktake_staff_id WHERE p.stocktake_staff_id = 46521

SQL query returns column with data from another column

I have a table Notices connected to tables Likes and Comments. When I return the notices for a user I also create columns: number_of_likes, number_of_comments and liked_by_me. The query is working correctly when the user making the query hasn't liked a notice (liked_by_me = 0) . But if they have (liked_by_me = 1) the value I get for number_of_likes is wrong and is the same as number_of_comments.
Example:
1)
- liked by me = false
- likes = 1
- comments = 5
Returned values:
- liked_by_me = 0
- number_of_likes = 1
- number_of_comments = 5
2)
- liked by me = true
- likes = 2
- comments = 5
Returned values:
- liked_by_me = 1
- number_of_likes = 5
- number_of_comments = 5
Here is the query I am using:
SELECT notices.*
, count(comment.id) as number_of_comments
, count(like1.user_id) as number_of_likes
, like2.user_id IS NOT NULL AS liked_by_me
, boards.name as board_name
FROM notices
LEFT JOIN comments as comment
ON (comment.notice_id = notices.id)
LEFT JOIN likes as like1
ON (like1.notice_id = notices.id)
LEFT JOIN likes as like2
ON (like2.notice_id = notices.id
AND like2.user_id = $1)
LEFT JOIN boards
ON (boards.id = notices.board_id)
LEFT OUTER JOIN board_users
ON (board_users.board_id = notices.board_id)
WHERE board_users.user_id = $1
GROUP BY notices.id
, boards.name
, like2.user_id
, userId
Any help would be appreciated. I have been on this for hours and I don't think I will be able to find the problem.
Thanks!
Solution:
Here is the working query
SELECT notices.*,
(SELECT COUNT(user_id) from likes WHERE likes.notice_id = notices.id) AS number_of_likes,
(SELECT user_id IS NOT NULL from likes WHERE likes.notice_id = notices.id AND likes.user_id = $1) AS liked_by_me,
count(comments.id) as number_of_comments, boards.name as board_name
FROM notices LEFT JOIN comments ON (comments.notice_id = notices.id)
LEFT JOIN boards ON (boards.id = notices.board_id)
LEFT OUTER JOIN board_users ON (board_users.board_id = notices.board_id)
WHERE board_users.user_id = $1 GROUP BY notices.id, boards.name", user);
You will have to use subeselects.
Excellent article on this problem: The GROUPing pitfall
TL;DR: Basically, you have to realize, that all your comments and likes are being multiplicated by one another. Try to display the result of the query without the group clause to see, that duplicate likes/comments are being counted.
EDIT: I didn't test this, but it's how the query might look:
(that is if user can only like one notice once, otherwise you would have to group current user likes too)
SELECT
notices.*,
comments.number_of_comments,
likes.number_of_likes
current_user_likes.user_id IS NOT NULL AS liked_by_me
boards.name AS board_name
FROM notices
LEFT JOIN (
SELECT
COUNT(*) AS number_of_comments,
notice_id
FROM comments
GROUP BY notice_id
) AS comments ON comments.notice_id = notices.id
LEFT JOIN (
SELECT
COUNT(*) AS number_of_likes,
notice_id
FROM likes
GROUP BY notice_id
) AS likes ON likes.notice_id = notices.id
LEFT JOIN likes AS current_user_likes
ON current_user_likes.notice_id = notices.id
AND current_user_likes.user_id = $1
LEFT JOIN boards ON boards.id = notices.board_id
INNER JOIN board_users
ON board_users.board_id = notices.board_id
AND board_users.user_id = $1;

Selecting from three tables

I am trying to SELECT from one table and count from two other tables based on the rows from the first table. I tried the following code below but the rows keep coming empty.
SELECT list.id, list.title, list.body, list.poster, list.created_at, count(comments.id) as comcount, count(supports.topic_id) as supcount
FROM (
SELECT *
FROM topics
ORDER BY created_at DESC
LIMIT 5
) AS list, comments, supports
WHERE
list.id = comments.id OR
list.id = supports.topic_id
Through in this scenario table topics has only two rows and tables comments and supports have no rows in them, but yet still I should be able to get two rows with their aliases supcount and comcount each having a value 0 as an output.
I got the solution to the above but am trying something else with the solution provided which I explained in the comment area of the solution provided.
SELECT
t.id,
t.title,
t.body,
t.poster,
t.created_at,
s.supporter,
IFNULL((SELECT COUNT(*) FROM comments c WHERE c.id = t.id), 0) AS comcount,
IFNULL((SELECT COUNT(*) FROM supports s WHERE s.topic_id = t.id), 0) AS supcount,
CASE WHEN (s.supporter = "Davies Alex") THEN '1' ELSE '0' END sup,
CASE WHEN (c.commenter = "Davies Alex") THEN '1' ELSE '0' END com
FROM topics t, comments c, supports s
ORDER BY created_at DESC
This gonna be working, give a try (using subquery for just counting entries in another table is more suitable):
SELECT
id,
title,
body,
poster,
created_at,
IFNULL((SELECT COUNT(*) FROM comments c WHERE c.id = t.id), 0) AS comcount,
IFNULL((SELECT COUNT(*) FROM supports s WHERE s.topic_id = t.id), 0) AS supcount
FROM topics t
ORDER BY created_at DESC
LIMIT 5
Update for new requirement:
SELECT
t.id,
t.title,
t.body,
t.poster,
t.created_at,
s.supporter,
IFNULL(COUNT(c.id), 0) AS comcount,
IFNULL(COUNT(s.id), 0) AS supcount,
SUM(IF(s.supporter IS NOT NULL AND s.supporter = "Davies Alex", 1, 0)) > 0 AS sup,
SUM(IF(c.commenter IS NOT NULL AND c.commenter = "Davies Alex", 1, 0)) > 0 AS com
FROM topics t
LEFT JOIN comments c ON c.id = t.id
LEFT JOIN supports s ON s.topic_id = t.id
GROUP BY t.id
ORDER BY created_at DESC
In your query, you require list.id to either match comments.id or supports.topic_id. If you use an outer join, you'll be able to retrieve data from the initial table even though the joined tables don't match or contain any data.
SELECT
topics.id, topics.title, topics.body, topics.poster, list.created_at,
count(comments.id) as comcount,
count(supports.topic_id) as supcount
FROM lists
LEFT JOIN comments ON comments.id = topics.id
LEFT JOIN supports ON supports.topic_id = topics.id
ORDER BY created_at DESC
LIMIT 5

MySQL display rows where value IS NULL or equal to X

userPosts.value can contain one of two values: 0 or 1.
I am Left Joining userPosts to my Posts table.
I want to get all posts from my Posts table where userPosts.value = 0 as well as all posts that do not have any userPosts.value at all (thus, NULL).
The following only get me posts where value = 0 but no NULL:
SELECT * FROM $wpdb->posts
LEFT JOIN userPosts ON ($wpdb->posts.ID = userPosts.postID)
WHERE userPosts.value != 1
ORDER BY $wpdb->posts.post_date DESC
The following only gets me posts where value = NULL:
SELECT * FROM $wpdb->posts
LEFT JOIN userPosts ON ($wpdb->posts.ID = userPosts.postID)
WHERE userPosts.value IS NULL
ORDER BY $wpdb->posts.post_date DESC
but this yields no results at all:
SELECT * FROM $wpdb->posts
LEFT JOIN userPosts ON ($wpdb->posts.ID = userPosts.postID)
WHERE userPosts.value = 0
AND userPosts.value IS NULL
ORDER BY $wpdb->posts.post_date DESC
and this does get me posts with value = 0 as well as NULL but it repeats all my NULL posts three times!
SELECT * FROM $wpdb->posts
LEFT JOIN userPosts ON ($wpdb->posts.ID = userPosts.postID)
WHERE userPosts.value = 0
OR userPosts.value IS NULL
ORDER BY $wpdb->posts.post_date DESC
So what am I doing wrong?
Try to use parenthasis on OR condition (userContests.value = 0 OR userContests.value IS NULL)
SELECT * FROM $wpdb->posts
LEFT JOIN userPosts ON ($wpdb->posts.ID = userPosts.postID)
WHERE (userContests.value = 0
OR userContests.value IS NULL)
ORDER BY $wpdb->posts.post_date DESC
You partially answered your own question in the title: OR not AND, but try using DISTINCT:
SELECT DISTINCT * FROM $wpdb->posts -- Note "DISTINCT"
LEFT JOIN userPosts ON ($wpdb->posts.ID = userPosts.postID)
WHERE userContests.value = 0
OR userContests.value IS NULL -- Note "OR"
ORDER BY $wpdb->posts.post_date DESC
(x = 0) AND (x is NULL) - a single field cannot be two values at the same time. No surprise that you get no results at all, because you've specified a where condition that is impossible to satisfy.
As for the rest of the query. You use $wdpd->posts as your source table, but then use a table named userContests in the where clause. Does $wpdb->posts resolve to userContests? If so, why make the table name dynamic in one place and hard-coded it in another?

Some sort of join statement?

How do I put these two queries into a single query?
select count(id) as cnt from {$site_id}.proofingv2_packages where active='1'
select count(id) as cnt from {$site_id}.proofingv2_package_options where active='1' and parent={$row["id"]} order by sort
$row['id'] is the id field from the first query. I am trying to determine if there are any valid packages. A valid package must be active and have at least 1 active option. Running 2 queries for this doesn't seem right.
Can anyone help?
select count(id) as cnt from
{$site_id}.proofingv2_packages pp
INNER JOIN
{$site_id}.proofingv2_package_options
pt ON pp.active = pt.Active AND
pp.Active = 1
if the id is the PK or FK on the same on both tables use this query
select count(id) as cnt from
{$site_id}.proofingv2_packages pp
INNER JOIN {$site_id}.proofingv2_package_options pt ON pp.id= pt.id
AND pp.Active = 1
SELECT IF(count(*) > 0, 1, 0) AS isValid
FROM {$site_id}.proofingv2_packages pp
INNER JOIN {$site_id}.proofingv2_package_options ppo ON ppo.parent = pp.id
WHERE pp.active = '1'
AND ppo.active = '1'
This should return 1 if there are valid packages or 0 if not