MySQL display rows where value IS NULL or equal to X - mysql

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?

Related

MySQL Multiple INNER JOIN + GROUP BY not working as expected

I am generating a Member Leaderboard based on some field values.. Using Below SQL i am getting those values...
SELECT ue1.user_id,
ue1.meta_value coins ,
ue3.meta_value user_rank ,
ue2.meta_value gems,
COUNT(ue4.user_id) quiz_count,
COUNT(ue5.user_id) video_watch_count,
ue1.meta_value + ue3.meta_value + ue2.meta_value total_points
FROM `wp_usermeta` as ue1
INNER JOIN `wp_usermeta` as ue2 ON ue2.user_id = ue1.user_id
AND ue1.meta_key = '_coin_points'
AND ue2.meta_key = '_gem_points'
INNER JOIN `wp_usermeta` as ue3 ON ue3.user_id = ue1.user_id
AND ue3.meta_key = '_user_rank'
INNER JOIN `wp_gamipress_user_earnings` as ue4 ON ue4.user_id = ue1.user_id
AND ue4.post_type = 'quiz-game-master'
INNER JOIN `wp_gamipress_user_earnings` as ue5 ON ue5.user_id = ue1.user_id
AND ue5.post_type = 'video-game-master'
WHERE ue1.meta_value > 0
AND ue2.meta_value > 0
GROUP BY ue1.user_id, ue1.meta_value, ue2.meta_value, ue3.meta_value, ue4.user_id, ue5.user_id
ORDER BY total_points DESC LIMIT 0, 50
What i am getting is... Not Expected Query Result
See? video_watch_count is copying quiz_count value.. I don't know why? Would appreciate if you could help me out here.
Check you join statement. For both quiz_count, video_watch_count, you select data from table wp_gamipress_user_earnings. For each entry if join condition satisfied it will return user_id from corresponding table.
Finally you group it using user_id which is common to both join results.That's why you get same count.

MySQL query taking too much time

query taking 1 minute to fetch results
SELECT
`jp`.`id`,
`jp`.`title` AS game_title,
`jp`.`game_type`,
`jp`.`state_abb` AS game_state,
`jp`.`location` AS game_city,
`jp`.`zipcode` AS game_zipcode,
`jp`.`modified_on`,
`jp`.`posted_on`,
`jp`.`game_referal_amount`,
`jp`.`games_referal_amount_type`,
`jp`.`status`,
`jp`.`is_flaged`,
`u`.`id` AS employer_id,
`u`.`email` AS employer_email,
`u`.`name` AS employer_name,
`jf`.`name` AS game_function,
`jp`.`game_freeze_status`,
`jp`.`game_statistics`,
`jp`.`ats_value`,
`jp`.`integration_id`,
`u`.`account_manager_id`,
`jp`.`model_game`,
`jp`.`group_id`,
(CASE
WHEN jp.group_id != '0' THEN gm.group_name
ELSE 'NA'
END) AS group_name,
`jp`.`priority_game`,
(CASE
WHEN jp.country != 'US' THEN jp.country_name
ELSE ''
END) AS game_country,
IFNULL((CASE
WHEN
`jp`.`account_manager_id` IS NULL
OR `jp`.`account_manager_id` = 0
THEN
(SELECT
(CASE
WHEN
account_manager_id IS NULL
OR account_manager_id = 0
THEN
`u`.`account_manager_id`
ELSE account_manager_id
END) AS account_manager_id
FROM
user_user
WHERE
id = (SELECT
user_id
FROM
game_user_assigned
WHERE
game_id = `jp`.`id`
LIMIT 1))
ELSE `jp`.`account_manager_id`
END),
`u`.`account_manager_id`) AS acc,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '1'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS somewhatgame,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '2'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS verygamecommitted,
(SELECT
COUNT(recach_limit_id)
FROM
recach_limit
WHERE
recach_limit = '3'
AND recach_limit_game_id = rpr.recach_limit_game_id) AS notgame,
(SELECT
COUNT(joa.id) AS applicationcount
FROM
game_refer_to_member jrmm
INNER JOIN
game_refer jrr ON jrr.id = jrmm.rid
INNER JOIN
game_applied joa ON jrmm.id = joa.referred_by
WHERE
jrmm.STATUS = '1'
AND jrr.referby_user_id IN (SELECT
ab_testing_user_id
FROM
ab_testing)
AND joa.game_post_id = rpr.recach_limit_game_id
AND (rpr.recach_limit = 1
OR rpr.recach_limit = 2)) AS gamecount
FROM
(`game_post` AS jp)
JOIN
`user_info` AS u ON `jp`.`user_user_id` = `u`.`id`
JOIN
`game_functional` jf ON `jp`.`game_functional_id` = `jf`.`id`
LEFT JOIN
`group_musesm` gm ON `gm`.`group_id` = `jp`.`group_id`
LEFT JOIN
`recach_limit` rpr ON `jp`.`id` = `rpr`.`recach_limit_game_id`
WHERE
`jp`.`status` != '3'
GROUP BY `jp`.`id`
ORDER BY `posted_on` DESC
LIMIT 10
I would first suggest not nesting select statements because this will cause an n^x performance hit on every xth level and I see at least 3 levels of selects inside this query.
Add index
INDEX(status, posted_on)
Move LIMIT inside
Then, instead of saying
FROM (`game_post` AS jp)
say
FROM ( SELECT id FROM game_post
WHERE status != 3
ORDER BY posted_on DESC
LIMIT 10 ) AS ids
JOIN game_post AS jp USING(id)
(I am assuming that the PK of jp is (id)?)
That should efficiently use the new index to get the 10 ids needed. Then it will reach back into game_post to get the other columns.
LEFT
Also, don't say LEFT unless you need it. It costs something to generate NULLs that you may not be needing.
Is GROUP BY necessary?
If you remove the GROUP BY, does it show dup ids? The above changes may have eliminated the need.
IN(SELECT) may optimize poorly
Change
AND jrr.referby_user_id IN ( SELECT ab_testing_user_id
FROM ab_testing )
to
AND EXISTS ( SELECT * FROM ab_testing
WHERE ab_testing_user_id = jrr.referby_user_id )
(This change may or may not help, depending on the version you are running.)
More
Please provide EXPLAIN SELECT if you need further assistance.

SELECT inside IF statement

SELECT jargons.jargon as jargon,
jargons.description as description,
jargons.example as example,
IF(jargons.rootJargon != 0, (SELECT jargon FROM jargons WHERE id = jargons.rootJargon), NULL) as rootJargonName
FROM jargons
LEFT JOIN users ON users.id = jargons.addedBy
ORDER BY jargons.id DESC
I have two rows inside jargons table:
"id" "jargon" "description" "example" "rootJargonName" "rootJargon"
"2" "Child" "jd" "1" NULL 1
"1" Root" "sad" "1" NULL 0
Why does the rootJargonName returns null instead of Root on Child row?
What I was trying to do is that if rootJargon column is not equals to zero then select the row with the id that specified in the column which is not equals to zero.
It's likely a table alias issue you're seeing, but you can rewrite this using a LEFT JOIN:
SELECT J.jargon as jargon,
J.description as description,
J.example as example,
R.jargon As rootJargonName
FROM jargons as J
LEFT JOIN users as U ON U.id = J.addedBy
LEFT JOIN jargons as R ON J.rootJargon = R.ID
ORDER BY J.id DESC
If you would like to keep the IF() function, you can use the following, however I recommend using the LEFT JOIN.
SELECT J.jargon as jargon,
J.description as description,
J.example as example,
IF(J.rootJargon != 0, (SELECT jargon FROM jargons as R WHERE R.id = J.rootJargon), NULL) as rootJargonName
FROM jargons as J
LEFT JOIN users as U ON U.id = J.addedBy
ORDER BY J.id DESC
why dont you try a case
like:
SELECT jargons.jargon as jargon,
jargons.description as description,
jargons.example as example,
CASE
WHEN (jargons.rootJargon == 0) THEN NULL
WHEN (jargons.rootJargon != 0) THEN
(SELECT jargon FROM jargons WHERE id = jargons.rootJargon)
END) AS 'rootJargonName'
FROM jargons
LEFT JOIN users ON users.id = jargons.addedBy
ORDER BY jargons.id DESC
I'm probably wrong somewhere in the syntax but i think thats the idea....

MySQL case when using JOIN/GROUP BY

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

how to select previous record with LEFT JOINed tables in MySQL?

I'm struggleing to get the following to work:
# prev
SELECT klha.buyerID < PARAMETER_1
FROM agents AS v
LEFT JOIN seller_authorized AS klhs
ON klhs.agent= v.agentID
AND klhs.iln = v.seller
AND v.`status` = 'auth'
LEFT JOIN cust_list AS klha
ON klha.buyerID = klhs.userID
AND klha.accountNo = klhs.accountNo
WHERE v.iln = PARAMETER_2
AND klhs.acccountNo IS NOT NULL
ORDER BY klha.buyerID
LIMIT 1
;
END
The left joins are working as I'm using them in another procedure to select ALL relevent records. The problem is with my attempt to select the previous record.
I'm passing in a buyerID and need to get back the id of the previous record.
Question:
Can anyone point me to the correct syntax?
EDIT:
If I run this in MySQL, I'm getting "0" as resultset
Thanks!
SOLUTION:
Got it to work like this:
# prev
SELECT klha.buyerID
FROM agents AS v
LEFT JOIN seller_authorized AS klhs
ON klhs.agent= v.agentID
AND klhs.iln = v.seller
AND v.`status` = 'auth'
LEFT JOIN cust_list AS klha
ON klha.buyerID = klhs.userID
AND klha.accountNo = klhs.accountNo
WHERE v.iln = PARAMETER_2
AND klhs.acccountNo IS NOT NULL
AND klha.buyerID < PARAMETER_1
ORDER BY klha.buyerID
LIMIT 1
;
Easier than thought :-) Thanks #Henrique Ordine
If I understand correctly what you need, adding this condition to your where clause should do the trick:
and klha.buyerID = (select max(buyerID) from agents where buyerID < PARAMETER_1)
Like this:
SELECT klha.buyerID
FROM agents AS v
LEFT JOIN seller_authorized AS klhs
ON klhs.agent= v.agentID
AND klhs.iln = v.seller
AND v.`status` = 'auth'
LEFT JOIN cust_list AS klha
ON klha.buyerID = klhs.userID
AND klha.accountNo = klhs.accountNo
WHERE v.iln = PARAMETER_2
AND klhs.acccountNo IS NOT NULL
and klha.buyerID = (select max(buyerID) from agents
where buyerID < PARAMETER_1)
ORDER BY klha.buyerID
LIMIT 1