MySQL CASE with GROUP BY count - mysql

I have these three queries
SELECT COUNT(question_id) AS correct_count, uID FROM mytable WHERE id
>= 0 AND id <= 1000 AND correct = 1 AND answer_id IS NOT NULL GROUP BY user_id
SELECT COUNT(question_id) AS incorrect_count, uID FROM mytable WHERE id >= 0 AND id <= 1000 AND correct !=1 AND answer_id IS NOT NULL GROUP BY user_id
SELECT COUNT(question_id) AS null_count, uID FROM mytable WHERE id >= 0 AND id <= 1000 AND answer_id IS NULL GROUP BY user_id
How can I join this as a single query using CASE or IF ?

SELECT user_id,
sum(id >= 0 AND id <= 1000 AND correct = 1 AND answer_id IS NOT NULL) AS correctCnt,
sum(id >= 0 AND id <= 1000 AND correct !=1 AND answer_id IS NOT NULL) AS incorrectCnt,
sum(id >= 0 AND id <= 1000 AND answer_id IS NULL) as nullCnt
FROM mytable
GROUP BY user_id

count only counts non-null items, so you could convert the where clauses to case expressions that return null when they do not match:
SELECT user_id,
COUNT (CASE WHEN id >= 0 AND id <= 1000 AND correct = 1 AND answer_id IS NOT NULL THEN 1 ELSE NULL) AS correct_count,
COUNT (CASE WHEN id >= 0 AND id <= 1000 AND correct !=1 AND answer_id IS NOT NULL THEN 1 ELSE NULL) AS incorrect_count,
COUNT (CASE WHEN WHERE id >= 0 AND id <= 1000 AND answer_id IS NULL) AS null_count
FROM mytable
GROUP BY user_id
Note that all these case statements share some conditions, so those could be extracted to a where clause:
SELECT user_id,
COUNT (CASE WHEN correct = 1 AND answer_id IS NOT NULL THEN 1 ELSE NULL) AS correct_count,
COUNT (CASE WHEN correct !=1 AND answer_id IS NOT NULL THEN 1 ELSE NULL) AS incorrect_count,
COUNT (CASE WHEN WHERE answer_id IS NULL THEN 1 ELSE NULL) AS null_count
FROM mytable
WHERE id >= 0 AND id <= 1000
GROUP BY user_id

Related

How make request more readable and scalable?

i have request:
SELECT user_id FROM merchant_data
WHERE user_id IN (
SELECT user_id FROM merchant_data
WHERE merchant_id = 1134
AND created_date = '2022-12-02'
GROUP BY user_id
HAVING COUNT(*) > 2)
AND merchant_id = 1167
AND created_date = '2022-12-02'
GROUP BY user_id
HAVING COUNT(*) = 2;
That request return me data from something like log table. In this case i need to get all users that have 2 more rows with merchant_id == 1134 and 2 rows merchant_id == 1167. But how make it for 4 or 5 or 6 condition like merchant_id == ...?
SELECT user_id FROM merchant_data
WHERE created_date = '2022-12-02'
AND merchant_id IN (1134, 1167, 1186, ...)
GROUP BY user_id
HAVING SUM(merchant_id = 1134) >= 2
AND SUM(merchant_id = 1167) >= 2
AND SUM(merchant_id = 1186) >= 2
AND ...
That depends on an odd MySQL feature that booleans are literally the integer values 1 for true and 0 for false, so you can SUM() a boolean expression. You can't do that in standard SQL.
You could make it more standard SQL by using CASE expressions with no ELSE clause. CASE returns NULL if there is no match, and COUNT() will ignore NULLs.
SELECT user_id FROM merchant_data
WHERE created_date = '2022-12-02'
AND merchant_id IN (1134, 1167, 1186, ...)
GROUP BY user_id
HAVING COUNT(CASE merchant_id WHEN 1134 THEN 1 END) >= 2
AND COUNT(CASE merchant_id WHEN 1167 THEN 1 END) >= 2
AND COUNT(CASE merchant_id WHEN 1186 THEN 1 END) >= 2
AND ...

sql query issue in record

I am getting problem in record using following query
SELECT user_id FROM temp
WHERE
(value = 1 AND field_id = 11) AND
value = 1 AND field_id = 12
Here is the table.
I should get record of 101 user_id.
Any one idea on this?
You need to aggregate by user:
SELECT user_id
FROM temp
GROUP BY user_id
HAVING
SUM(CASE WHEN value = 1 AND field_id = 11 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN value = 1 AND field_id = 12 THEN 1 ELSE 0 END) > 0;
try this sql select DISTINCT user_id from temp where value=1 and (field_id=12 or field_id=11)
You can also use where clause :
select user_id
from table t
where value = 1 and field_id in (11, 12)
group by user_id
having count(distinct field_id) = 2;

MYSQL Error code 1248 Every derived table must have it's own alias

MYSQL Error code 1248 Every derived table must have it's own alias
select supplier_id, supplier_name, strong_answers from
(select campaign_suppliers.id supplier_id, campaign_suppliers.supplier_name supplier_name,
count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) strong_answers
from supplier_answers join campaign_suppliers on (supplier_answers.supplier_id = campaign_suppliers.id)
where supplier_answers.campaign_id = 1 group by campaign_suppliers.id, campaign_suppliers.supplier_name
having count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) >=
(select count(distinct supplier_answers.question_index) from supplier_answers where campaign_id = 1))
where strong_answers >= (select count(distinct supplier_answers.question_index) from supplier_answers where campaign_id = 1)
You need a table name alias for the from ( ... ) t see // <---- symbol below
select t.supplier_id, t.supplier_name, t.strong_answers from (
select campaign_suppliers.id supplier_id, campaign_suppliers.supplier_name supplier_name,
count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) strong_answers
from supplier_answers join campaign_suppliers on (supplier_answers.supplier_id = campaign_suppliers.id)
where supplier_answers.campaign_id = 1 group by campaign_suppliers.id, campaign_suppliers.supplier_name
having count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) >=
(select count(distinct supplier_answers.question_index)
from supplier_answers where campaign_id = 1)) t //<---- here you need a table name eg: t
where t.strong_answers >= (select count(distinct supplier_answers.question_index) from supplier_answers where campaign_id = 1)

A count is returning NULL when it should just be zero

I have a table that tracks users trustworthiness.
+-----------------+-----------------+-------------+
| user_id_1 | user_id_2 | is_trusted |
+-----------------+-----------------+-------------+
| 1 | 2 | 0 |
...
Where 1 is trusted and 0 is not. If there is no negative feedback I get NULL for the value. Is there a way to just get the positive - 0?
select tr2.user_id_2 user,
((select count(*) plus
from trust_ratings tr
where is_trusted = 1 and
tr2.user_id_2 = tr.user_id_2
group by tr.user_id_2)
-
(select count(*) minus
from trust_ratings tr
where is_trusted = 0 and
tr2.user_id_2 = tr.user_id_2
group by tr.user_id_2)) as score
from trust_ratings tr2
group by user;
You could use case when:
select user_id_2 user,
sum(case is_trusted when 1 then 1 else -1 end) as score
from trust_ratings
group by user;
Or:
select user_id_2 user,
sum(is_trusted * 2 - 1) as score
from trust_ratings
group by user;
Use COALESCE():
select tr2.user_id_2 user,
(
coalesce(
(select count(*) plus
from trust_ratings tr
where is_trusted = 1 and
tr2.user_id_2 = tr.user_id_2
group by tr.user_id_2), 0)
-
coalesce(
(select count(*) minus
from trust_ratings tr
where is_trusted = 0 and
tr2.user_id_2 = tr.user_id_2
group by tr.user_id_2), 0)
) as score
from trust_ratings tr2
group by user;

multiple selects on one table

I have a table called list and i have to extract the following.
fields are id and date
If date<20120401 then count on id >>>> give result
If date>20120401 then count on id >>>> give result
if there are 20 items of date<20120401 and 30 items of date>20120401 of an idnumber xyz
then the result should be...
xyz 20 30
I have done like ...
select
(select count(id) from list where id='xyz' and date<20120401) as date1,
(select count(id) from list where id='xyz' and date>20120401) as date2;
the result is 20 30
but how to print the idnumber?
SELECT
id,
SUM(CASE WHEN date < 20120401 THEN 1 ELSE 0 END) AS date1,
SUM(CASE WHEN date > 20120401 THEN 1 ELSE 0 END) AS date2,
FROM list
WHERE id = 'xyz'
GROUP BY id
UPDATE:
SELECT
list.id,
idmaster.idlocation,
SUM(CASE WHEN list.date < 20120401 THEN 1 ELSE 0 END) AS date1,
SUM(CASE WHEN list.date > 20120401 THEN 1 ELSE 0 END) AS date2,
FROM list
INNER JOIN idmaster ON list.id = idmaster.idnumber
WHERE list.id = 'xyz'
GROUP BY id
Try
select id, count(id) from list where id='xyz' and date < 20120401
union
select id, count(id) from list where id='xyz' and date > 20120401
You are looking for GROUP BY clause and maybe something like this:
SELECT
l2.id,
(SELECT COUNT(id)
FROM list l1
WHERE l1.id = l2.id AND date < 20120401) AS date1,
(SELECT COUNT(id)
FROM list l1
WHERE l1.id = l2.id AND date > 20120401) AS date2
FROM
list l2
GROUP BY
l2.id
There are more cost effective methods to get desired result, but this is the easiest to understand.
Try this:
SELECT
id,
SUM(CASE WHEN date < 20120401
THEN 1 ELSE 0 END) AS date1,
SUM(CASE WHEN date > 20120401
THEN 1 ELSE 0 END) AS date2,
FROM list
WHERE id = 'xyz'
GROUP BY id