WHERE subquery = 0 - mysql

I'm trying to write a query which checks if a question have any answers which are marked as a correct answer.
Now I tried using a subquery and I tried setting the subquery as a user-defined variable.
Test #1
SELECT
#id := `id` AS `id`, `title`
FROM
`eu_questions`
WHERE
CAST((SELECT COUNT(`id`) FROM `eu_answers` WHERE `question_id` = #id AND `correct` = 1) AS UNSIGNED) = 0
ORDER BY `id` ASC
LIMIT 0, 10;
Test #2
SELECT
#id := `id` AS `id`,
#count_correct := (SELECT COUNT(`id`) FROM `eu_answers` WHERE `question_id` = #id AND `correct` = 1) AS `count_correct`
FROM
`eu_questions`
WHERE
CAST(#count_correct AS UNSIGNED) = 0
ORDER BY `id` ASC
LIMIT 0, 10;
The queries doesn't result in errors, they simply return 0 results and I don't get why? I tried comparing the user-defined variable while selected and that seems to work and return the correct value, so that simply bugs me even more!
This is how I checked it:
SELECT
#id := `id` AS `id`,
#count_correct := (SELECT COUNT(`id`) FROM `eu_answers` WHERE `question_id` = #id AND `correct` = 1) AS `count_correct`,
CAST(#count_correct AS UNSIGNED) = 0
FROM
`eu_questions`
ORDER BY `id` ASC
LIMIT 0, 10;
Answer - Thanks to Branko Dimitrijevic
I used his example and ended up with this query, which fits my needs.
SELECT *
FROM `eu_questions`
WHERE
1 != ANY (
SELECT COUNT(`id`)
FROM `eu_answers`
WHERE `question_id` = `eu_questions`.`id`
AND `correct` = 1
)
ORDER BY `id` ASC
LIMIT 0, 10;

Here you go:
SELECT *
FROM eu_questions
WHERE 1 = ANY (
SELECT correct
FROM eu_answers
WHERE question_id = eu_questions.id
);
[SQL Fiddle]
Add extra WHERE and LIMIT conditions as desired...

You can LEFT JOIN on the answers table and use a where clause to keep only questions without correct answer.
SELECT
`eu_questions`.`id`, `title`
FROM
`eu_questions`
LEFT JOIN
`eu_answers` ON `question_id` = `eu_questions`.`id` AND `correct` = 1
WHERE
`eu_questions`.`id` IS NULL
ORDER BY `eu_questions`.`id` ASC
LIMIT 0, 10;

Related

How to fetch rows with prefered where clause, but also with a fallback?

I have a query (transaction) like this for fetching items from a table. I have a where clause of confirmed = '1', but would like to fallback to ignoring that where clause when no rows are found with the clause.
How can I do this in MySQL Server?
START TRANSACTION;
SELECT #id := `id`,`item`
FROM `queue_items`
WHERE `processed_at` IS NULL AND `completed_at` IS NULL AND confirmed = '1' ORDER BY `id` ASC
LIMIT 1
FOR UPDATE;
UPDATE `queue_items` SET `processed_at` = #processedAt, `worker_id` = #workerId WHERE `id` = #id;
COMMIT;
You could use a conditional sort:
SELECT #id := `id`, `item`
FROM `queue_items`
WHERE `processed_at` IS NULL AND `completed_at` IS NULL
ORDER BY (confirmed = 1) DESC, `id`
LIMIT 1

Set MYSQL WHERE condition from previous SELECT

I have the following MySQL query
SELECT `category`
FROM `jeopardy_questions`
WHERE `amount` = "$2,000"
GROUP BY `category`
HAVING COUNT(*) > 4
ORDER BY RAND() LIMIT 1
This will grab me a random category where there is at least 5 questions in that category.
Now I want to grab all the rows for that category. So how can I do a second SELECT WHERE category is equal to the category returned from the previous query?
I tried the following but I believe the RAND() is causing it to crash/timeout.
SELECT *
FROM `jeopardy_questions`
WHERE `category` = (
SELECT `category`
FROM `jeopardy_questions`
WHERE `amount` = "$2,000"
GROUP BY `category`
HAVING COUNT(*) > 4
ORDER BY RAND() LIMIT 1
)
You can use the above query as a subquery. Something like this:
SELECT *
FROM `jeopardy_questions`
WHERE `category` = (
SELECT `category`
FROM `jeopardy_questions`
WHERE `amount` = "$2,000"
GROUP BY `category`
HAVING COUNT(*) > 4
ORDER BY RAND() LIMIT 1
)

Between but NOT inclusive with sub query

I have seen replies to this when using dates but not with sub queries. I have the following
SELECT *
FROM `TEST`
where `ID` BETWEEN
(SELECT `ID` FROM `TEST` WHERE `Home_Team`
REGEXP 'saturday|sunday|monday|tuesday|wednesday|thursday|friday'
order by ID asc LIMIT 1)
AND
(SELECT `ID` FROM `TEST` WHERE `Home_Team`
REGEXP 'saturday|sunday|monday|tuesday|wednesday|thursday|friday'
order by ID asc LIMIT 1,1)
I would like the results not to be inclusive. unfortunately, im not having any luck with any of < > =
Best I'm aware, a BETWEEN b and c is syntactic sugar for b <= a and a <= c, i.e. always inclusive. To make it exclusive, rewrite it as b < a and a < c.
Is ID an integer? If so, just +1 and -1 where appropriate:
SELECT *
FROM `TEST`
where `ID` BETWEEN
(SELECT `ID` FROM `TEST` WHERE `Home_Team`
REGEXP 'saturday|sunday|monday|tuesday|wednesday|thursday|friday'
order by ID asc LIMIT 1) + 1
AND
(SELECT `ID` FROM `TEST` WHERE `Home_Team`
REGEXP 'saturday|sunday|monday|tuesday|wednesday|thursday|friday'
order by ID asc LIMIT 1,1) - 1

select last row only if a where condition is met

I have a column for messages and I am trying to figure out how I should display messages in "sent" folder.
I run the following query:
SELECT
`text`,
`created`
FROM
`messages`
WHERE
`status` = 1
ORDER BY `created` DESC
LIMIT 1
I want to introduce a condition so that result is returned only when the last row with status = 1 also has user_from = $user (If the last row has user_to = $user, then nothing should be returned).
What should my query be?
you can use a subquery
select `text`, `created` from T1
( SELECT
`text`,
`created`
FROM
`messages`
WHERE
`status` = 1
ORDER BY `created` DESC
LIMIT 1) T1
where `user_from` = $user and `user_to` != $user
If I understand your question correctly, do you want to do this:
SELECT
`text`,
`created`
FROM
`messages`
WHERE
`status` = 1
AND `user_from` = $user
AND `user_to` != $user
ORDER BY `created` DESC
LIMIT 1
Of course you need to replace $user with your string, or use a prepared statement to insert the variable into the query.
Select the latest message with status=1 and then use it as a nested query and check your conditions to output this one row result or not:
select `text`, `created`
from
(
SELECT
`text`,
`created`,
user_from,
user_to
FROM
`messages`
WHERE
`status` = 1
ORDER BY `created` DESC
LIMIT 1
) t
where (user_from = $user)
and (not (user_to = $user))

How do I combine these two Select queries with an OR case

I want to select all rows where WHERE (uid = {$uid} OR uid = **HERE** ) where **HERE** is the cids retreived from query 2 below.
Query 1:
SELECT * FROM `t_activities`
WHERE (`uid` = {$uid} OR `uid` = **HERE** )
AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
And Query 2:
SELECT `cid` FROM `t_con` WHERE `uid` = {$uid} AND `flag` = 1
SELECT * FROM `t_activities`
WHERE (`uid` = {$uid} OR `uid` in (SELECT `cid`
FROM `t_con`
WHERE `uid` = {$uid} AND `flag` = 1))
AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
You can do this as a join as well:
SELECT *
FROM `t_activities` ta left outer join
(SELECT `cid`
FROM `t_con`
WHERE `uid` = {$uid} AND `flag` = 1)
) tc
on ta = tc.cid
WHERE (`uid` = {$uid} OR tc.`uid` is not null) AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
By the way, as a SQL statement the "GROUP BY fid" looks very strange. This is allowed in mysql, but I think it is a bad practice. It is much better to be explicit about what you are doing:
SELECT fid, min(<field1>) as Field1, . . .
This helps prevent mistakes when you go back to the query or try to modify it.