SQL using CASE in count and group by - mysql

I'm using CASE to categorize data in the table and count them but the results aren't accurate
live demo [here]
select DATE(date) as day, count(*),
count(distinct case when name = 'fruit' then 1 else 0 end) as fruits,
count(distinct case when name = 'vege' then 1 else 0 end) as vege,
count(distinct case when name = 'sweets' then 1 else 0 end) as sweets
from food
group by day
with rollup
I'm not sure if the issue is with CASE or in the string matching = because there's no 'sweets' still it counts 1?
any pointers I'd be grateful

Your problem is that COUNT counts every result that is not NULL. In your case you are using:
COUNT(distinct case when name = 'sweets' then 1 else 0 end)
So, when the name is not sweets, it counts the 0. Furthermore, since you are using DISTINCT, it counts just one or two values. You should either use SUM or remove the DISTINCT and the ELSE 0:
SELECT DATE(date) as day,
COUNT(*),
SUM(CASE WHEN name = 'fruit' THEN 1 ELSE 0 END) as fruits,
SUM(CASE WHEN name = 'vege' THEN 1 ELSE 0 END) as vege,
SUM(CASE WHEN name = 'sweets' THEN 1 ELSE 0 END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Or:
SELECT DATE(date) as day,
COUNT(*),
COUNT(CASE WHEN name = 'fruit' THEN 1 ELSE NULL END) as fruits,
COUNT(CASE WHEN name = 'vege' THEN 1 ELSE NULL END) as vege,
COUNT(CASE WHEN name = 'sweets' THEN 1 ELSE NULL END) as sweets
FROM food
GROUP BY DAY
WITH ROLLUP
Here is a modified sqlfiddle.

You can't group by an alias. You have to group by the expression.
group by date(date)

You can group on an Alias:
SELECT
FROM_UNIXTIME(UnixTimeField, '%Y') AS 'Year'
,FROM_UNIXTIME(UnixTimeField, '%m') AS 'Month'
FROM table p
GROUP BY Year, Month

Related

How to sum all count(case) subcolumns?

I'm creating a table that can count all 'abnormal' data from three columns and sum those columns as the total.
SELECT
COUNT(CASE WHEN p_eyes <> 'Normal' THEN 1 END) AS 'abnormalEyes',
COUNT(CASE WHEN p_ears <> 'Normal' THEN 1 END) AS 'abnormalEars',
COUNT(CASE WHEN p_nose <> 'Normal' THEN 1 END) AS 'abnormalNose'
FROM student_physical_record_exam_grade_eleven;
This will count all the not 'Normal' from those three columns.
Is there any way I can total those three columns as 'Eyes/Ears/Nose'?
If you want to just sum these results, you could add them. The easiest way of doing this is with a subquery:
SELECT *, abnormalEyes + abnormalEars + abnormalNose AS totalAbnormal
FROM (SELECT COUNT(CASE WHEN p_eyes <> 'Normal' THEN 1 END) AS abnormalEyes,
COUNT(CASE WHEN p_ears <> 'Normal' THEN 1 END) AS abnormalEars,
COUNT(CASE WHEN p_nose <> 'Normal' THEN 1 END) AS abnormalNose
FROM student_physical_record_exam_grade_eleven) t

Count different values in a column, while doing total and group by different column values

We have a table with data from different nodes and one of the column will have status report as "compliant or non-compliant", sample data as below
I want to filter the table in such a way that if any of the checks on a node shows non compliant, it should be flagged as non-compliant and rest as compliant. Using below query i am able to do it
SELECT COUNT(*) AS total_nodes,
SUM(fully_compliant = 0) AS Non_compliant_nodes,
SUM(fully_compliant = 1) AS compliant_nodes
FROM (
SELECT Node, CASE WHEN SUM(Status = 'Compliant') = COUNT(*) THEN 1 ELSE 0 END AS fully_compliant
FROM your_table GROUP BY Node
)
Now, i want to group and split the result by dept as below, how can i achieve this
I think you're looking for this:
select dept,
count(*) as total_nodes,
sum(case when non_compliant_chk = 0 then 1 else 0 end) as compliant_nodes,
sum(case when non_compliant_chk > 0 then 1 else 0 end) as non_compliant_nodes
from (
select dept,
node,
sum(case when 'Non-Compliant' then 1 else 0 end) as non_compliant_chk
from your_table
group by dept,
node
) v
group by dept;
With few modifications to what Brian suggested, I am able to get the desired result
select dept,
count(*) as total_nodes,
sum(case when non_compliant_chk = 0 then 1 else 0 end) as compliant_nodes,
sum(case when non_compliant_chk > 0 then 1 else 0 end) as non_compliant_nodes
from (
select dept,
node,
COUNT(CASE WHEN Compliance-Status = 'Non-Compliant' THEN 1 END) 'non_compliant_chk'
from table WHERE DOR >= DATE(NOW()) - INTERVAL 7 DAY
group by Dept,
Node
) v
group by Dept;

Select sum with a group by inside a group by

With this example iformation table:
How can i output this information?
I'm trying this query,
but it's just returning me the total number of 'PART' rows for each 'NAMES'.
SELECT
NAMES
, SUM(PART = "F001") AS SUM_F001
, SUM(PART = "F002") AS SUM_F002
, SUM(PART = "F003") AS SUM_F003
FROM
MY_TABLE
GROUP BY NAMES ASC
You are pretty close with your current query.
But you need to use the query below to correctly pivot.
SELECT
NAMES
, MAX(CASE WHEN PART = 'F001' THEN QTY ELSE 0 END) AS F001
, MAX(CASE WHEN PART = 'F002' THEN QTY ELSE 0 END) AS F002
, MAX(CASE WHEN PART = 'F003' THEN QTY ELSE 0 END) AS F003
, SUM(QTY) AS alias
FROM
FROM
MY_TABLE
GROUP BY
NAMES # Don't use ASC OR DESC on GROUP BY because it's deprecated
ORDER BY
NAMES ASC
U can use the query as follows
SELECT NAMES , SUM(CASE WHEN PART = 'F001' THEN 1 ELSE 0 END) AS F001 , SUM(CASE WHEN PART = 'F002' THEN 1 ELSE 0 END) AS F002 , SUM(CASE WHEN PART = 'F003' THEN 1 ELSE 0 END) AS F003 , SUM(QTY) AS alias FROM FROM MY_TABLE GROUP BY NAMES ORDER BY NAMES ASC

i want MySQL query result in same row

SELECT sum(case when (gender)=1 THEN 1 ELSE 0 END),
GROUP_CONCAT(sum(case when (gender)=2 THEN 1 ELSE 0 END) SEPARATOR ' ') as combine
from family_member_tbl
GROUP BY gender
NO, you can't nest grouping function like that. Rather get the sum first and then group_concat() like
select sum_1, sum_2, group_concat(sum_2) as combine
from (
SELECT gender,
sum(case when gender = 1 THEN 1 ELSE 0 END) as sum_1,
sum(case when gender = 2 THEN 1 ELSE 0 END) as sum_2
from family_member_tbl
GROUP BY gender ) xxx
group by gender;

How get TOP from query? [duplicate]

This question already has answers here:
Is there an alternative to TOP in MySQL?
(4 answers)
Closed 6 years ago.
SELECT
user_id,
count(*) total,
sum(case when type = 'yes' then 1 else 0 end) as type_1,
sum(case when type = 'no' then 1 else 0 end) as type_2
FROM history
GROUP by user_id
How get TOP 100 rows from this query which have max count type = 'yes' ?
You can use LIMIT to limit the number of results and use an ORDER BY to order it so the results are in descending order of total.
SELECT
user_id,
count(*) total,
sum(case when type = 'yes' then 1 else 0 end) as type_1,
sum(case when type = 'no' then 1 else 0 end) as type_2
FROM history
GROUP by user_id
ORDER BY type_1 DESC
LIMIT 100
You should add WHERE statement to your query to add conditional statement
Also, I can see that you are using mysql, so that means you should order your data by argument descending and limit result to 100
SELECT
user_id,
count(*) total,
sum(case when type = 'yes' then 1 else 0 end) as type_1,
sum(case when type = 'no' then 1 else 0 end) as type_2
FROM history
WHERE type='yes'
GROUP by user_id
ORDER BY total DESC
LIMIT 100
SELECT
user_id,
count(*) total,
sum(case when type = 'yes' then 1 else 0 end) as type_1,
sum(case when type = 'no' then 1 else 0 end) as type_2
FROM history
GROUP by user_id
ORDER by type_1 DESC
LIMIT 100