Return a count when response_val=4 is found between response_key 95 to 98 corresponding to each uhid and group by month
|response_key | response_val | month | uhid |
|---------------------------------------------|
| 95 | 4 | 2019-09| 14569|
| 96 | 4 | 2019-09| 14569|
| 97 | 5 | 2019-09| 14569|
| 98 | 5 | 2019-09| 14569|
| 95 | 5 | 2019-09| 13256|
| 96 | 5 | 2019-09| 13256|
| 97 | 5 | 2019-09| 13256|
| 98 | 5 | 2019-09| 13256|
| 95 | 5 | 2019-09| 25689|
| 96 | 5 | 2019-09| 25689|
| 97 | 5 | 2019-09| 25689|
| 98 | 5 | 2019-09| 25689|
|---------------------------------------------|
I tried sql query as
SELECT month,
COUNT(CASE
WHEN `response_key` IN (95,96,97,98) and `response_val`='5'
THEN 1 ELSE NULL END) AS 'yes',
COUNT(CASE
WHEN `response_key` IN (81,82,83,84,85,86,87) and `response_val`='4'
THEN 1 ELSE NULL END) AS 'no'
FROM audit WHERE group by month
but it return the count when all the response_key have value 4.
I expect result as
| count | month |
-----------------
| 1 |2019-09|
Maybe the following will get you what you want:
SELECT `month`,
COUNT(CASE response_val WHEN 4 THEN 1 END) AS `yes`,
COUNT(CASE response_val WHEN 5 THEN 1 END) AS `no`
FROM audit
WHERE response_key between 95 AND 98
GROUP BY `month`
I simplified your case statements and move the response_key condition into the where-clause (the ELSE part in a CASE statement is only necessary if you want to return a value other than null).
You can find a working demo here: https://rextester.com/PCN24609
The resulting counts from this query are:
month yes no
2019-09 1 11
Well, you can swap the order of your output columns as you like, and if you are only interested in the response_val=4 counts do it like here:
SELECT COUNT(CASE response_val WHEN 4 THEN 1 END) AS `count`,
`month`
FROM audit
WHERE response_key between 95 AND 98
GROUP BY `month`
demo: https://rextester.com/JEV40175
result:
| count | month |
-------------------
| 1 | 2019-09 |
Edit:
"Return a count when response_val=4 is found between response_key 95
to 98 corresponding to each uhid and group by month"
This would imply that you simply group over uhid too, like shown here:
SELECT COUNT(CASE response_val WHEN 4 THEN 1 END) AS `count`,
`month`,uhid
FROM audit
WHERE response_key between 95 AND 98
GROUP BY `month`,uhid;
-- results:
count month uhid
0 2019-09 13256
2 2019-09 14569
1 2019-09 25689
Or, if you want all uhid-counts in one row per month:
SELECT `month`,
COUNT(CASE uhid WHEN 14569 THEN 1 END) AS `cnt_14569`,
COUNT(CASE uhid WHEN 13256 THEN 1 END) AS `cnt_13256`,
COUNT(CASE uhid WHEN 25689 THEN 1 END) AS `cnt_25689`
FROM audit
WHERE response_key between 95 AND 98 AND response_val=4
GROUP BY `month`,uhid
-- results:
month cnt_14569 cnt_13256 cnt_25689
2019-09 2 0 0
2019-09 0 0 1
demo: https://rextester.com/WXQ73318
2. Edit: Following your latest comment, the following might fulfil your requirements
("list the number of distinct users with response_val=4 for each month"):
SELECT COUNT(`count`) usrcnt, `month` FROM (
SELECT COUNT(CASE response_val WHEN 4 THEN 1 END) AS `count`,`month`,uhid
FROM audit WHERE response_key between 95 AND 98
GROUP BY `month`,uhid
) tbl WHERE `count`>0 GROUP BY `month`;
-- or, even shorter:
SELECT COUNT(DISTINCT CASE response_val WHEN 4 THEN uhid END) AS `count`,`month`
FROM audit WHERE response_key between 95 AND 98
GROUP BY `month`;
-- same result from both queries:
usrcnt month
2 2019-09
demo: https://rextester.com/UGN73913
The latest queries are based on these table values:
response_key response_val month uhid
95 4 2019-09 14569
96 4 2019-09 14569
97 5 2019-09 14569
98 5 2019-09 14569
95 5 2019-09 13256
96 5 2019-09 13256
97 5 2019-09 13256
98 5 2019-09 13256
95 5 2019-09 25689
96 4 2019-09 25689
97 5 2019-09 25689
98 5 2019-09 25689
Related
| recharge_table |
r_date
r_name
r_amount
01-01-2020
Phineas
120
01-02-2020
Phineas
130
01-03-2020
Phineas
199
01-04-2020
Candes
299
03-01-2020
Candes
149
03-02-2020
Ferb
149
03-03-2020
Platypus
349
05-08-2020
Ferb
459
09-11-2020
Candes
199
06-10-2020
Platypus
299
find last two amounts of each customer based on dates, and in ascending order of name.
output must be as below:-
| Candes | 199 | 299 |
| Ferb | 459 | 159 |
| Phineas | 199 | 130 |
| Platypus | 299 | 349 |
If Possible, also give explanation.
You can use row_number() and conditional aggregation:
select r_name,
max(case when seqnum = 1 then r_amount end),
max(case when seqnum = 2 then r_amount end)
from (select r.*,
row_number() over (partition by r_name order by r_date desc) as seqnum
from recharge_table r
) r
where seqnum <= 2
group by r_name;
I have a dataset like this as shown below, for example row 1, 0 purchase is made for the item priced at $3, 3 purchases are made for item priced at $30. I would need to write a query to provide the summary of how many passes purchased, by categorising the prices into price range of "0-10", "11-20", "21-30", "31-40". I assume case when should be used but I am unsure of how. Please help.
+-----------------+-----------------+--------------------------+--------------------------+
| price_category1 | price_category2 | purchase_count_category1 | purchase_count_category2 |
+-----------------+-----------------+--------------------------+--------------------------+
| 3 | 30 | 0 | 3 |
| 20 | 6 | 1 | 4 |
| 25 | 11 | 4 | 0 |
| 17 | 12 | 0 | 1 |
+-----------------+-----------------+--------------------------+--------------------------+
+------+-------+-------+-------+
| 0-10 | 11-20 | 21-30 | 31-40 |
+------+-------+-------+-------+
| 4 | 2 | 7 | 0 |
+------+-------+-------+-------+
You can try below.
Working Solution
WITH MAIN
AS (SELECT 3 AS price_category1,
30 AS price_category2,
0 purchase_count_category1,
3 AS purchase_count_category2
FROM DUAL
UNION ALL
SELECT 20 AS price_category1,
6 AS price_category2,
1 purchase_count_category1,
4 AS purchase_count_category2
FROM DUAL
UNION ALL
SELECT 25 AS price_category1,
11 AS price_category2,
4 purchase_count_category1,
0 AS purchase_count_category2
FROM DUAL
UNION ALL
SELECT 17 AS price_category1,
12 AS price_category2,
0 purchase_count_category1,
1 AS purchase_count_category2
FROM DUAL),
M2
AS (SELECT price_category1 CAT, purchase_count_category1 CNT FROM MAIN
UNION
SELECT price_category2, purchase_count_category2 FROM MAIN)
SELECT CASE
WHEN CAT >= 0 AND CAT < 11 THEN '0-10'
WHEN CAT >= 11 AND CAT < 21 THEN '11-20'
WHEN CAT >= 21 AND CAT < 31 THEN '21-30'
END
CAT,
SUM (CNT) SUMM
FROM M2
GROUP BY CASE
WHEN CAT >= 0 AND CAT < 11 THEN '0-10'
WHEN CAT >= 11 AND CAT < 21 THEN '11-20'
WHEN CAT >= 21 AND CAT < 31 THEN '21-30'
END
SELECT SUM(CASE WHEN price_category1 BETWEEN 0 AND 10
THEN purchase_count_category1
END) + SUM(CASE WHEN price_category2 BETWEEN 0 AND 10
THEN purchase_count_category2
END) AS `0-10`,
SUM(CASE WHEN price_category1 BETWEEN 11 AND 20
THEN purchase_count_category1
END) + SUM(CASE WHEN price_category2 BETWEEN 11 AND 20
THEN purchase_count_category2
END) AS `11-20`,
SUM(CASE WHEN price_category1 BETWEEN 21 AND 30
THEN purchase_count_category1
END) + SUM(CASE WHEN price_category2 BETWEEN 21 AND 30
THEN purchase_count_category2
END) AS `21-30`
FROM source_table
or
SELECT SUM(CASE WHEN cat BETWEEN 0 AND 10
THEN cnt
END ) AS `0-10`,
SUM(CASE WHEN cat BETWEEN 11 AND 20
THEN cnt
END ) AS `11-20`,
SUM(CASE WHEN cat BETWEEN 21 AND 30
THEN cnt
END ) AS `21-30`
FROM ( SELECT price_category1 cat, purchase_count_category1 cnt
FROM source_table
UNION ALL
SELECT price_category2, purchase_count_category2
FROM source_table ) src
PS. This solution gives "horizontal" output - one row with all needed statistic. If you need "vertical" output then use the solution provided by ismetguzelgun.
Pay attention - my solution is not extendable (if you need to alter the ranges amount or borders you must alter the query text) whereas alternative solution can be extended easily after converting hardcoded ranges borders to according CTE or (the best) additional criteria table.
My source table (wplott_wpkl_winner) contains the field "lottery_number" that carries 1 to 6 digit numbers and the corresponding "draw_date".
lottery_number | draw_date
==================================
0024 | 2018-11-10
4456 | 2018-11-10
3895 | 2018-11-10
4557 | 2018-11-10
4225 | 2018-11-10
2896 | 2018-11-10
3354 | 2018-11-10
1895 | 2018-11-10
78466 | 2018-11-10
998556 | 2018-11-10
My current MYSQL query is as below (I am trying to group the data into ranges)
select
count(case when wplott_wpkl_winner.lottery_number between 0 and 999 then 1 end) `0-999`,
count(case when wplott_wpkl_winner.lottery_number between 1000 and 1999 then 1 end) `1000-1999`,
count(case when wplott_wpkl_winner.lottery_number between 2000 and 2999 then 1 end) `2000-2999`,
count(case when wplott_wpkl_winner.lottery_number between 3000 and 3999 then 1 end) `3000-3999`,
count(case when wplott_wpkl_winner.lottery_number between 4000 and 4999 then 1 end) `4000-4999`,
count(case when wplott_wpkl_winner.lottery_number between 5000 and 5999 then 1 end) `5000-5999`,
count(case when wplott_wpkl_winner.lottery_number between 6000 and 6999 then 1 end) `6000-6999`,
count(case when wplott_wpkl_winner.lottery_number between 7000 and 7999 then 1 end) `7000-7999`,
count(case when wplott_wpkl_winner.lottery_number between 8000 and 8999 then 1 end) `8000-8999`,
count(case when wplott_wpkl_winner.lottery_number between 9000 and 9999 then 1 end) `9000-9999`
from wplott_wpkl_winner
where CHAR_LENGTH(wplott_wpkl_winner.lottery_number) = 4 AND wplott_wpkl_winner.draw_date > '2013-06-30'
It provides the below output
0-999 | 1000-1999 | 2000-2999 | 3000-3999 | 4000- 4999 .... etc
=====================================================================
1 | 1 | 1 | 2 | 3
However, I would like to get the output in the below format.
Range | Count
=======================
0-999 | 1
1000-1999 | 1
2000-2999 | 1
3000-3999 | 2
4000-4999 | 3
.
.
.
Any help is highly appreciated. I did search in SO for a similar answer but none of the answers helped my particular case.
Thanks in advance!
One approach uses a series of unions:
SELECT
`range`,
count
FROM
(
SELECT 1 AS pos, '0-999' AS `range`, COUNT(*) AS count
FROM wplott_wpkl_winner
WHERE draw_date > '2013-06-30' AND lottery_number BETWEEN 0 AND 999
UNION ALL
SELECT 2, '1000-1999', COUNT(*)
FROM wplott_wpkl_winner
WHERE draw_date > '2013-06-30' AND lottery_number BETWEEN 1000 AND 1999
UNION ALL
... -- fill in remaining ranges here
) t
ORDER BY pos;
Note that I introduce a computed column pos so that we may maintain the desired ordering of the ranges in the final output. Also, I removed the check on the CHAR_LENGTH of the lottery_number, since the conditional sums already handle this logic.
This is a view i created
SELECT YEAR(CURRENT_TIMESTAMP) - YEAR(c.date_of_birth) - (RIGHT(CURRENT_TIMESTAMP, 5) < RIGHT(c.date_of_birth, 5)) as age, count(a.id) as occurences, a.celex_id,
COUNT(CASE WHEN c.gender = 'MALE' THEN c.id END) as males,
COUNT(CASE WHEN c.gender = 'FEMALE' THEN c.id END) as females,
COUNT(CASE WHEN c.gender IS NULL THEN c.id END) as unknowns
FROM consumer c, account a
WHERE a.consumer_id = c.id
GROUP BY age, a.celex_id;
This results in:
age | occurences | celex_id | male | female | unknowns
------------------------------------------------------
16 | 1 | 1 | 0 | 1 | 0
65 | 1 | 1 | 1 | 0 | 0
66 | 1 | 1 | 0 | 1 | 0
69 | 1 | 1 | 0 | 0 | 1
And so on.
Now, I have made a query with a case statement, but I am unable to group by the cases, this is the query
SELECT
CASE
WHEN age BETWEEN 0 AND 10 THEN '0-10'
WHEN age BETWEEN 11 AND 20 THEN '11-20'
WHEN age BETWEEN 21 AND 30 THEN '21-30'
WHEN age BETWEEN 31 AND 40 THEN '31-40'
WHEN age BETWEEN 41 AND 50 THEN '41-50'
WHEN age BETWEEN 51 AND 60 THEN '51-60'
WHEN age BETWEEN 61 AND 70 THEN '61-70'
WHEN age BETWEEN 71 AND 80 THEN '71-80'
WHEN age BETWEEN 81 AND 90 THEN '81-90'
WHEN age BETWEEN 91 AND 100 THEN '91-100'
WHEN age > 100 THEN 'Greater than 100'
ELSE 'Unknown'
END AS age_range, males, females, unknowns
FROM age_gender_occurences
WHERE celex_id = 1
GROUP BY age_range, males, females, unknowns
This gives
age_range | males | females | unknowns
--------------------------------------
11-20 | 0 | 1 | 0
21-30 | 0 | 1 | 0
61-70 | 0 | 1 | 0
61-70 | 1 | 0 | 0
61-70 | 0 | 0 | 1
I have tried replicating the case statement directly in the GROUP BY clause, but this does not work. Can someone shed some light over how i can get the age_range to become one-liners? (like 61-70 becoming 1 line instead of 3)
You are missing the aggregation functions. I would write this in terms of the original tables:
SELECT (CASE WHEN age BETWEEN 0 AND 10 THEN '0-10'
WHEN age BETWEEN 11 AND 20 THEN '11-20'
WHEN age BETWEEN 21 AND 30 THEN '21-30'
WHEN age BETWEEN 31 AND 40 THEN '31-40'
WHEN age BETWEEN 41 AND 50 THEN '41-50'
WHEN age BETWEEN 51 AND 60 THEN '51-60'
WHEN age BETWEEN 61 AND 70 THEN '61-70'
WHEN age BETWEEN 71 AND 80 THEN '71-80'
WHEN age BETWEEN 81 AND 90 THEN '81-90'
WHEN age BETWEEN 91 AND 100 THEN '91-100'
WHEN age > 100 THEN 'Greater than 100'
ELSE 'Unknown'
END) AS age_range,
SUM(CASE WHEN c.gender = 'MALE' THEN 1 ELSE 0 END) as males,
SUM(CASE WHEN c.gender = 'FEMALE' THEN 1 ELSE 0 END) as females,
SUM(CASE WHEN c.gender IS NULL THEN 1 ELSE 0 END) as unknowns
FROM consumer c JOIN
account a
ON a.consumer_id = c.id
WHERE celex_id = 1
GROUP BY age_range;
If you want to write it in terms of the view (which seems overkill):
SELECT (CASE WHEN age BETWEEN 0 AND 10 THEN '0-10'
WHEN age BETWEEN 11 AND 20 THEN '11-20'
WHEN age BETWEEN 21 AND 30 THEN '21-30'
WHEN age BETWEEN 31 AND 40 THEN '31-40'
WHEN age BETWEEN 41 AND 50 THEN '41-50'
WHEN age BETWEEN 51 AND 60 THEN '51-60'
WHEN age BETWEEN 61 AND 70 THEN '61-70'
WHEN age BETWEEN 71 AND 80 THEN '71-80'
WHEN age BETWEEN 81 AND 90 THEN '81-90'
WHEN age BETWEEN 91 AND 100 THEN '91-100'
WHEN age > 100 THEN 'Greater than 100'
ELSE 'Unknown'
END) AS age_range,
SUM(males) as males,
SUM(females) as females,
SUM(unknowns) as unknowns
FROM age_gender_occurences
WHERE celex_id = 1
GROUP BY age_range;
In other words, you need to aggregate again. And, in fact, MySQL will do two aggregations in this case, which is why I recommend the simpler version of just using the original tables.
This question already has answers here:
need to return two sets of data with two different where clauses
(2 answers)
Closed 8 years ago.
I'm building a feedback tool, and I have a feedback table that the following structure:
ID | Satisfaction | Timestamp
--------------------------------------------
1 0 2014-01-01 00:00:00
2 5 2014-01-01 00:00:00
3 10 2014-01-02 00:00:00
4 5 2014-01-02 00:00:00
5 10 2014-01-03 00:00:00
6 0 2014-01-03 00:00:00
7 10 2014-01-03 00:00:00
8 5 2014-01-04 00:00:00
9 5 2014-01-04 00:00:00
How can I get a daily count of the number of each "satisfaction" value?
For example:
Date | 0's | 5's | 10's
--------------------------------------
2014-01-01 | 1 | 1 | 0
2014-01-02 | 0 | 1 | 1
2014-01-03 | 1 | 0 | 2
2014-01-04 | 0 | 2 | 0
I'd imagine it involves a GROUP BY timestamp, but I'm not sure how to select
The simplest way to pivot this data in MySQL:
select date(timestamp),
sum(satisfaction = 0) as zeroes,
sum(satisfaction = 5) as fives,
sum(satisfaction = 10) as tens
from feedback
group by date(timestamp);
Solved! I was able to grab the counts of the individual values using a combination of sum() and case statements.
SELECT
DATE(timestamp),
IFNULL(sum(case when satisfaction = 0 then 1 end), 0) as 'unhappy',
IFNULL(sum(case when satisfaction = 5 then 1 end), 0) as 'neutral',
IFNULL(sum(case when satisfaction = 10 then 1 end), 0) as 'happy'
FROM feedback
GROUP BY DATE(timestamp)