MySQL row count with different age ranges - mysql

I have a MySQL table as follows.
emp_no emp_name dob gender
1 A 1978-10-10 Male
2 B 1985-02-20 Female
3 C 1982-04-16 Female
4 D 1980-06-27 Male
Then I need to get the following result.
age_group No of Male No of Female Total
<25 1 0 1
25-35 0 1 1
35-50 0 1 1
>50 1 0 1
I used the following query to get this output.
SELECT TIMESTAMPDIFF(YEAR, dob, NOW()) AS age_group,
COUNT( IF( TIMESTAMPDIFF(YEAR, dob, NOW()) <25, 1, 0 ) ) AS ag_C,
COUNT( IF( TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN 25 AND 35 , 1, 0 ) ) AS ag_B,
COUNT( IF( TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN 35 AND 50 , 1, 0 ) ) AS ag_C,
COUNT( IF( TIMESTAMPDIFF(YEAR, dob, NOW()) >50, 1, 0 ) ) AS ag_D
FROM emp GROUP BY age_group
But I can not get the desired out put. Can anyone help me on this issue ?

try this
SELECT Case
when TIMESTAMPDIFF(YEAR, dob, NOW()) < 25 then '<25'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 25 and 35 then '25-35'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 36 and 50 then '36-50'
else '>50' END AS age_group,
sum(if(gender='Male', 1, 0)) as Male,
sum(if(gender='Female', 1, 0)) as Female,
COUNT(1) as total FROM emp
GROUP BY Case
when TIMESTAMPDIFF(YEAR, dob, NOW()) < 25 then '<25'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 25 and 35 then '25-35'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 36 and 50 then '36-50'
else '>50' END;

Try below:
SELECT Case
when TIMESTAMPDIFF(YEAR, dob, NOW()) < 25 then '<25'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 25 and 35 then '25-35'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 36 and 50 then '36-50'
else '>50' END AS age_group,
sum(case when gender='Male' then 1 end) as Male,
sum(case when gender='Female' then 1 end) as Female,
sum(case when gender in ('Male','Female') then 1 end) as total,
GROUP BY Case
when TIMESTAMPDIFF(YEAR, dob, NOW()) < 25 then '<25'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 25 and 35 then '25-35'
when TIMESTAMPDIFF(YEAR, dob, NOW()) between 36 and 50 then '36-50'
else '>50' END

You could try this:
select emp_no,
emp_name,
dob,
gender,
case when age < 25 then 1 else 0 end `<25`,
case when age >= 25 and age < 35 then 1 else 0 end `25-35`,
case when age >= 35 and age < 50 then 1 else 0 end `35-50`,
case when age >= 50 then 1 else 0 end `>=50`
from (
select emp_no,
emp_name,
dob,
gender,
year(now()) - year(dob) - (date_format(now(), '%m%d') < date_format(dob, '%m%d'))
age
from tbl
) a

use case when and sub-query
select
case when age_group < 25 then '<25',
case when age_group >= 25 and age_group < 35 then '25-35',
case when age_group >= 35 and age_group < 50 then '35-50',
case when age_group >= 50 then '>=50' else null end as age_grp,
sum(case when gender='Male' then 1 end) as Male,
sum(case when gender='Female' then 1 end) as Female,
sum(case when gender in ('Male','Female') then 1 else 0 end)
as total from
(
SELECT TIMESTAMPDIFF(YEAR, dob, NOW()) AS age_group,gender
FROM emp
) as t group by age_grp

Related

Mysql add an extra column at end instead of using a union

I am trying to combine two queries so the data shows up in one table. I am using a union to combine the two queries. However, everything is added to the same column, what do I change so the results from the different queries take up a new column.
Here is an image of the query result.
Here is my code
select * from(
SELECT
CASE
WHEN age BETWEEN 18 and 25 THEN 'Under 25'
WHEN age BETWEEN 25 and 40 THEN '25 - 40'
WHEN age >= 40 THEN 'Over 40'
WHEN age IS NULL THEN 'Not Filled In (NULL)'
END as age_range,
COUNT(*) AS count,
CASE
WHEN age between 18 and 25 THEN 1
WHEN age BETWEEN 25 and 40 THEN 2
WHEN age >= 40 THEN 8
WHEN age IS NULL THEN 9
END as ordinal
FROM (SELECT TIMESTAMPDIFF(YEAR, users.birthdate_on, CURDATE()) AS age FROM users
join subscriptions on users.id = subscriptions.user_id
where users.plan <> 'domain' and users.plan <> '' and users.plan <> 'domain_cpi' and users.birthdate_on is not null
) as derived
GROUP BY age_range
union
SELECT
CASE
WHEN age BETWEEN 18 and 25 THEN 'Under 25'
WHEN age BETWEEN 25 and 40 THEN '25 - 40'
WHEN age >= 40 THEN 'Over 40'
WHEN age IS NULL THEN 'Not Filled In (NULL)'
END as age_range2,
COUNT(*) AS count2,
CASE
WHEN age between 18 and 25 THEN 1
WHEN age BETWEEN 25 and 40 THEN 2
WHEN age >= 40 THEN 8
WHEN age IS NULL THEN 9
END as ordinal
FROM (SELECT TIMESTAMPDIFF(YEAR, users.birthdate_on, CURDATE()) AS age FROM users) as derived2
GROUP BY age_range2
) as test2
ORDER BY ordinal
I want the result so only one under 25 shows, but the two results for under 25 493 and 2046 are in different columns. Same for all other ranges
Sounds like you want to put a JOIN to derived.age_range ON test2.age_range2
SELECT
CASE
WHEN age BETWEEN 18 and 25 THEN 'Under 25'
WHEN age BETWEEN 25 and 40 THEN '25 - 40'
WHEN age >= 40 THEN 'Over 40'
WHEN age IS NULL THEN 'Not Filled In (NULL)'
END as age_range,
CASE
WHEN age between 18 and 25 THEN 1
WHEN age BETWEEN 25 and 40 THEN 2
WHEN age >= 40 THEN 8
WHEN age IS NULL THEN 9
END as ordinal,
count, count2
FROM (
SELECT
derived.age,
COUNT(*) AS count
FROM (
SELECT TIMESTAMPDIFF(YEAR, users.birthdate_on, CURDATE()) AS age FROM users
join subscriptions on users.id = subscriptions.user_id
where users.plan <> 'domain' and users.plan <> '' and users.plan <> 'domain_cpi' and users.birthdate_on is not null
GROUP BY age
) as derived
JOIN
SELECT
derived2.age,
COUNT(*) AS count2
FROM (
SELECT TIMESTAMPDIFF(YEAR, users.birthdate_on, CURDATE()) AS age FROM users
GROUP BY age
) as derived2
ON derived.age = derived2.age
)
ORDER BY ordinal ASC;
I don't believe you need 2 queries just a left join instead. The count() function ONLY increments for non-null values so you can have users counted even if they don't meet the subscription criteria.
SELECT
CASE
WHEN age BETWEEN 18 and 25 THEN 'Under 25'
WHEN age BETWEEN 25 and 40 THEN '25 - 40'
WHEN age >= 40 THEN 'Over 40'
WHEN age IS NULL THEN 'Not Filled In (NULL)'
END as age_range
, CASE
WHEN age between 18 and 25 THEN 1
WHEN age BETWEEN 25 and 40 THEN 2
WHEN age >= 40 THEN 8
WHEN age IS NULL THEN 9
END as ordinal
, COUNT(DISTINCT id) AS user_count # distinct might not be needed
, COUNT(subscriber_id) AS subscriber_count
FROM (
SELECT
users.id
, TIMESTAMPDIFF(YEAR, users.birthdate_on, CURDATE()) AS age
, subscriptions.user_id AS subscriber_id
FROM users
LEFT JOIN subscriptions ON users.id = subscriptions.user_id
AND users.plan <> 'domain'
AND users.plan <> ''
AND users.plan <> 'domain_cpi'
AND users.birthdate_on IS NOT NULL
) d
GROUP BY
CASE
WHEN age BETWEEN 18 and 25 THEN 'Under 25'
WHEN age BETWEEN 25 and 40 THEN '25 - 40'
WHEN age >= 40 THEN 'Over 40'
WHEN age IS NULL THEN 'Not Filled In (NULL)'
END
, CASE
WHEN age between 18 and 25 THEN 1
WHEN age BETWEEN 25 and 40 THEN 2
WHEN age >= 40 THEN 8
WHEN age IS NULL THEN 9
END

How can I JOIN static values and use them as GROUP BY identifier?

I have created a SELECT statement where I fetch the time difference from now to a certain date in my database.
SELECT
`username`,
TIMESTAMPDIFF(HOUR, `a_date`, NOW()) AS `timediff`
FROM
`User`
... results in something like
username | timediff
-------------------
john | 441
henry | 1624
mike | 4
kyle | NULL
Now I would like to group them into pre defined groups, e.g.
NULL
less than 20
greater than 20
How can I JOIN the above result with a static set of predefined values and how can I use those values as my grouping identifier?
group | amount
--------------
NULL | 1
lt 20 | 1
gt 20 | 2
You can use case statement with group by:
SELECT (CASE WHEN TIMESTAMPDIFF(HOUR, `a_date`, NOW()) < 20 THEN 'lt 20'
WHEN TIMESTAMPDIFF(HOUR, `a_date`, NOW()) >= 20 THEN 'gt 20'
END) as grp, COUNT(*)
FROM `User`
GROUP BY grp;
As a side note: I usually repeat the case statement in the group by, because many databases don't allow column aliases there:
SELECT (CASE WHEN TIMESTAMPDIFF(HOUR, `a_date`, NOW()) < 20 THEN 'lt 20'
WHEN TIMESTAMPDIFF(HOUR, `a_date`, NOW()) >= 20 THEN 'gt 20'
END) as grp, COUNT(*)
FROM `User`
GROUP BY (CASE WHEN TIMESTAMPDIFF(HOUR, `a_date`, NOW()) < 20 THEN 'lt 20'
WHEN TIMESTAMPDIFF(HOUR, `a_date`, NOW()) >= 20 THEN 'gt 20'
END);

Calculate percentage and total after create categories mysql

I've this query
SELECT
trage,
CASE trage
WHEN '<18' THEN SUM(CASE WHEN AGE <18 THEN 1 ELSE 0 END)
WHEN '18-24' THEN SUM(CASE WHEN AGE >= 18 AND AGE <= 24 THEN 1 ELSE 0 END)
WHEN '25-34' THEN SUM(CASE WHEN AGE >= 25 AND AGE <= 34 THEN 1 ELSE 0 END)
WHEN '35-44' THEN SUM(CASE WHEN AGE >= 35 AND AGE <= 44 THEN 1 ELSE 0 END)
WHEN '45-54' THEN SUM(CASE WHEN AGE >= 45 AND AGE <= 54 THEN 1 ELSE 0 END)
WHEN '>=55' THEN SUM(CASE WHEN AGE >= 55 THEN 1 ELSE 0 END)
END Total
FROM
( SELECT
t_personne.pers_date_naissance,
t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription)
- CASE
WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0
END AS AGE
FROM t_personne
) AS Total
CROSS JOIN
( SELECT '<18' trage UNION ALL
SELECT '18-24' UNION ALL
SELECT '25-34' UNION ALL
SELECT '35-44' UNION ALL
SELECT '45-54' UNION ALL
SELECT '>=55'
)a
GROUP BY trage
ORDER BY FIELD(trage, '<18', '18-24', '25-34', '35-44', '45-54', '>=55')
it give a table with two columns trage and Total for all categories
How to add a column percentage with a line TOTAL for the column Total and %
Thanks for your help
For the time being, you can't do this. To support this MySQL needs Window Function support which it still doesn't have. If you need functions like these I would recommend switching to PostgreSQL.
Also take a look at this question: MySql using correct syntax for the over clause

Calculate and create categories age display sum by column

Here is my query.
I calculate age, after i sum occurence for each categorie everything right.
SELECT
SUM(CASE WHEN AGE <18 THEN 1 ELSE 0 END) AS '<18',
SUM(CASE WHEN AGE >= 18 AND AGE <= 24 THEN 1 ELSE 0 END) AS '18-24',
SUM(CASE WHEN AGE >= 25 AND AGE <= 34 THEN 1 ELSE 0 END) AS '25-34',
SUM(CASE WHEN AGE >= 35 AND AGE <= 44 THEN 1 ELSE 0 END) AS '35-44',
SUM(CASE WHEN AGE >= 45 AND AGE <= 54 THEN 1 ELSE 0 END) AS '45-54',
SUM(CASE WHEN AGE >= 55 THEN 1 ELSE 0 END)AS '>=55'
FROM (SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) AS Total
give :
<18|18-24|25-34|35-44|45-54|>=55
67 |693 |1619 |1486 |616 |93
But I'd like this:
AGE |Total|
<18 |67 |
18-24|693 |
25-34|1619 |
35-44|1486 |
45-54|616 |
>=55 |93 |
you can use a cross join with the column name to transpose it
SELECT
age_range,
CASE age_range
WHEN '<18' THEN SUM(CASE WHEN AGE <18 THEN 1 ELSE 0 END)
WHEN '18-24' THEN SUM(CASE WHEN AGE >= 18 AND AGE <= 24 THEN 1 ELSE 0 END)
WHEN '25-34' THEN SUM(CASE WHEN AGE >= 25 AND AGE <= 34 THEN 1 ELSE 0 END)
WHEN '35-44' THEN SUM(CASE WHEN AGE >= 35 AND AGE <= 44 THEN 1 ELSE 0 END)
WHEN '45-54' THEN SUM(CASE WHEN AGE >= 45 AND AGE <= 54 THEN 1 ELSE 0 END)
WHEN '>=55' THEN SUM(CASE WHEN AGE >= 55 THEN 1 ELSE 0 END)
END value
FROM
( SELECT
t_personne.pers_date_naissance,
t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription)
- CASE
WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0
END AS AGE
FROM t_personne
) AS Total
CROSS JOIN
( SELECT '<18' age_range UNION ALL
SELECT '18-24' UNION ALL
SELECT '25-34' UNION ALL
SELECT '35-44' UNION ALL
SELECT '45-54' UNION ALL
SELECT '>=55'
)a
GROUP BY age_range
ORDER BY FIELD(age_range, '<18', '18-24', '25-34', '35-44', '45-54', '>=55')
FIDDLE DEMO
Not so elegant but it will work
SELECT
'<18' as AGE,COUNT(AGE) AS Total FROM
(SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) as Totals where AGE <18
UNION
SELECT
'18-24',COUNT(AGE) AS Total FROM
(SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) as Totals where AGE >= 18 AND AGE <= 24
UNION
SELECT
'25-34',COUNT(AGE) AS Total FROM
(SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) as Totals where AGE >= 25 AND AGE <= 34
UNION
SELECT
'35-44',COUNT(AGE) AS Total FROM
(SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) as Totals where AGE >= 35 AND AGE <= 44
UNION
SELECT
'45-54',COUNT(AGE) AS Total FROM
(SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) as Totals where AGE >= 45 AND AGE <= 54
UNION
SELECT
'>=55',COUNT(AGE) AS Total FROM
(SELECT t_personne.pers_date_naissance, t_personne.pers_date_inscription,
TIMESTAMPDIFF(Year, t_personne.pers_date_naissance, t_personne.pers_date_inscription) -
CASE WHEN MONTH(t_personne.pers_date_naissance) > MONTH(t_personne.pers_date_inscription)
OR (MONTH(t_personne.pers_date_naissance) = MONTH(t_personne.pers_date_inscription)
AND DAY(t_personne.pers_date_naissance) > DAY(t_personne.pers_date_inscription))
THEN 1 ELSE 0 END AS AGE
FROM t_personne) as Totals where AGE >= 55

Count records for each age range

I have a mysql table
TABLE name test
Id INT PRIMARY KEY
Lahir Date
Gender CHAR(1)
Nama Varchar(100)
id_desa CHAR(4)
How can I get report like this?
id_desa 0-10 11-20 21-30 31-40 41-50
10B 1 2 0 1 8
10C 2 4 7 1 0.
try
select
id_desa,
sum(case when FLOOR(DATEDIFF(Lahir,NOW())/365) between 0 and 10 then 1 else 0 end) as '0-10',
sum(case when FLOOR(DATEDIFF(Lahir,NOW())/365) between 11 and 20 then 1 else 0 end) as '11-20',
sum(case when FLOOR(DATEDIFF(Lahir,NOW())/365) between 21 and 30 then 1 else 0 end) as '21-30',
sum(case when FLOOR(DATEDIFF(Lahir,NOW())/365) between 31 and 40 then 1 else 0 end) as '31-40',
sum(case when FLOOR(DATEDIFF(Lahir,NOW())/365) between 41 and 50 then 1 else 0 end) as '41-50'
from tbl
You can try to use this query.
I assume that the table name is name_test.
SELECT id_desa,
(SELECT Count(*) FROM name_test WHERE DATE_FORMAT(FROM_DAYS(DATEDIFF(Now(),Lahir)), "%y")+0 BETWEEN 0 AND 10) as "0-10",
(SELECT Count(*) FROM name_test WHERE DATE_FORMAT(FROM_DAYS(DATEDIFF(Now(),Lahir)), "%y")+0 BETWEEN 11 AND 20) as "11-20",
(SELECT Count(*) FROM name_test WHERE DATE_FORMAT(FROM_DAYS(DATEDIFF(Now(),Lahir)), "%y")+0 BETWEEN 21 AND 30) as "21-30",
(SELECT Count(*) FROM name_test WHERE DATE_FORMAT(FROM_DAYS(DATEDIFF(Now(),Lahir)), "%y")+0 BETWEEN 31 AND 40) as "31-40",
(SELECT Count(*) FROM name_test WHERE DATE_FORMAT(FROM_DAYS(DATEDIFF(Now(),Lahir)), "%y")+0 BETWEEN 41 AND 50) as "41-50"
FROM name_test
MySQL has a very nice function called TIMESTAMPDIFF
SELECT
id_desa,
SUM(TIMESTAMPDIFF(YEAR, Lahir, CURRENT_DATE) BETWEEN 0 AND 10) `0-10`,
SUM(TIMESTAMPDIFF(YEAR, Lahir, CURRENT_DATE) BETWEEN 11 AND 20) `11-20`,
SUM(TIMESTAMPDIFF(YEAR, Lahir, CURRENT_DATE) BETWEEN 21 AND 30) `21-30`,
SUM(TIMESTAMPDIFF(YEAR, Lahir, CURRENT_DATE) BETWEEN 31 AND 40) `31-40`,
SUM(TIMESTAMPDIFF(YEAR, Lahir, CURRENT_DATE) BETWEEN 41 AND 50) `41-50`,
SUM(TIMESTAMPDIFF(YEAR, Lahir, CURRENT_DATE) > 50) `50+`
FROM tablename
GROUP BY id_desa