How to group number of users by age bands in mysql - mysql

Essentially I have a mysql database with users and their corresponding date of birth. I have also found the following bit of code that would help me find the users actual age from the date of birth. Finding date of birth What I need to do is find different "age bands" and count the amount of users in that age band. I have also found this example that shows exactly how to group this data. I want to calculate the age first and use it in the a way similar as shown in the following link. I have written the following code and am getting an error when running it:
SELECT DATE_FORMAT(NOW(), '%Y') -
DATE_FORMAT(data_of_birth, '%Y') -
(DATE_FORMAT(NOW(), '00-%m-%d') <
DATE_FORMAT(data_of_birth,
'00-%m-%d')) AS age, COUNT(*),
CASE
WHEN age >= 10 AND age <= 20 THEN '10-20'
WHEN age >=21 AND age <=30 THEN '21-30'
WHEN age >=31 AND age <=40 THEN '31-40'
WHEN age >=41 AND age <= 50 THEN '31-40'
WHEN age >=51 AND age <=60 THEN '51-60'
WHEN age >=61 THEN '61+'
END AS ageband
.. ..
GROUP BY ageband
I get an error stating that the field age is not known. Am I writing this incorrectly? I could easily write the whole block of code that calculates age where age is written in the case statement but this seems to be very inefficient. I am not very good at mysql (yet) and I know that there has to be a better way to do this. I guess my main question is if there is some sort of way to create a function inside a query and assign the output of that function to a value?

In this case you can use a subquery:
SELECT
COUNT(*),
CASE
WHEN age >=10 AND age <=20 THEN '10-20'
WHEN age >=21 AND age <=30 THEN '21-30'
WHEN age >=31 AND age <=40 THEN '31-40'
WHEN age >=41 AND age <=50 THEN '41-50'
WHEN age >=51 AND age <=60 THEN '51-60'
WHEN age >=61 THEN '61+'
END AS ageband
FROM
(
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(date_of_birth, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(date_of_birth, '00-%m-%d')) AS age,
.. ..
) as tbl
GROUP BY ageband;
So first it executes the subquery and builds a table of ages, than it aggregates the age value.

Related

Is it possible to create a single sql statement to fetch a list of people where their birthday celebration will fall in next 60 days

I have a table where it has some name and dateofbirth.
Refence data:
ABC, 1990-11-23
BCD, 1998-10-21
CDE, 1997-05-02
DEF, 2000-10-15
EFG, 1999-01-10
FGH, 1987-01-15
GHI, 1989-12-19
HIJ, 1986-12-09
I need a SQL query where I need to get the birthday celebration dates that is going to happen during the next 60 days ordered by celebration dates.
This is the query that I used till now.
SELECT *
FROM `friends`
WHERE ( DATE_FORMAT(`dob`, '%m%d') >= DATE_FORMAT(CURDATE(), '%m%d')
AND DATE_FORMAT(`dob`, '%m%d') <= DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 60 DAY), '%m%d')
ORDER BY DATE_FORMAT(`dob`, '%m%d');
It works ok if it runs during Jan to Oct. During November and December, the condition DATE_FORMAT(dob, '%m%d') <= DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 60 DAY), '%m%d') cannot apply. For example, the resulting comparison will be like 1209 < 0131 and fails.
The result that I expect to get when executed on Dec 2, 2022 is
HIJ, 1986-12-09
GHI, 1989-12-19
EFG, 1999-01-10
FGH, 1987-01-15
How do I do this in one single query?
The thread mentioned in the comment to your question uses things like adding 365.25 days to get this to work. I think this solution might be more reliable.
You can construct this years' birthday by extracting the month and day from the date of birth, and concatenating the current year to it using STR_TO_DATE.
Then you can check using a CASE statement if this years' birthday has already passed, in which case you add a year to that birthday, because that will be the next birthday for name. Then you can check if the result of that CASE statement is BETWEEN today and 60 days from now.
I used a CTE to make it clearer to read. DBfiddle here.
WITH cte as (
SELECT
-- First determine this years (year of current date) birthday
-- by constructing it from the current year, month of birth and day of birth
STR_TO_DATE(
CONCAT(YEAR(CURDATE()),'-', MONTH(dob), '-', DAY(dob)),
'%Y-%m-%d') AS this_years_birthday,
name,
dob
FROM friends
)
SELECT cte.name, cte.dob
FROM cte
WHERE
-- If the birthday is still in this year
-- Use this years' birthday
-- else add a year to this years' birthday
-- Then filter it to be between today and 60 days from now
CASE WHEN this_years_birthday >= CURDATE()
THEN this_years_birthday
ELSE DATE_ADD(this_years_birthday, INTERVAL 1 YEAR) END
BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 60 DAY)
ORDER BY MONTH(cte.dob) DESC
name
dob
GHI
1989-12-19
HIJ
1986-12-09
EFG
1999-01-10
FGH
1987-01-15

people's age calcuation

I have table called person with id, name, dob 3 columns,
sample data follows:
INSERT INTO person(id,name,dob) VALUES
(1,'Ton','1964-01-02'),
(2,'Luck','1960-01-20').....
select
name, dob,
current_timestamp() as curren_date,
timestampdiff(year, dob, curdate()) as age,
timestampdiff(month, dob, curdate()) as age,
timestampdiff(day, dob, curdate()) as age,
date_format(dob, '%m'),
month(curdate()),
timestampdiff(month, date_format(dob, '%m'),month(curdate())),
DATEDIFF(dob, curdate()) AS DateDiff
from
person
So i don't know what i miss, the above code can calculate the age in years- not very accurate i believe, but ideally i want to calculate the people's age in year, month, days, e.g Ton 55 years 1 month 3 days, and also want to calculate his next birthday due date, e.g next birthday date: 11 month 10 days left etc
Thanks
You can calculate the age in years accurately as:
select (case when date_format(dob, '%m-%d') >= date_format(now(), '%m-%d')
then year(now()) - year(dob)
else year(now()) - year(dob) - 1
end)
I believe that this handles all edge cases -- such as leap years. It accurately counts the age up to the day.
I've never been a fan of years/months/days, because I think the definition is unclear. You will need to provide sample of what you want.

How to get user details between two ages from dob without age column mysql

I want to get details of the user between two ages from date of birth. My conditions are,
Calculate the age from DOB
Find the user details between two ages
My tables is,
id username phone dob
-------------------------------------
1 Jithin 123456 31/12/1990
2 Binoy 235612 12/12/1991
3 Jibin 353453 12/12/1996
I have create mysql query as below
SELECT username, DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(dob, '%Y') - (DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(dob, '00-%m-%d')) AS age FROM tbl_user WHERE age BETWEEN 20 AND 30
But the above code shows an error the column age not found. How to fix this problem. Any alternate way to find age from dob and compare it.
It does not work because you can't use an alias right away. Use a subquery around it or repeat the calculation. There is a shorter way to calculate it:
SELECT TIMESTAMPDIFF(YEAR, dob, CURDATE()) AS age
from tbl_user
where TIMESTAMPDIFF(YEAR, dob, CURDATE()) between 20 and 30
You could use subquery:
SELECT *
FROM (SELECT username,
DATE_FORMAT(NOW(), '%Y') - DATE_FORMAT(dob, '%Y') -
(DATE_FORMAT(NOW(), '00-%m-%d') < DATE_FORMAT(dob, '00-%m-%d')) AS age
FROM tbl_user) sub
WHERE sub.age BETWEEN 20 AND 30;
Column age from SELECT clause is not visible in WHERE at the same level. You could either wrap it with subquery or repeat entire expression.

Two different date types in column

I am trying to create a age group array in mysql.
SELECT
COUNT(*),
CASE
when age < 60 THEN '<60'
when age >= 61 AND age <= 65 then '61-65'
when age >= 66 AND age <= 70 then '66-70'
when age >= 71 AND age <= 75 then '71-75'
when age >= 76 AND age <= 80 then '76-80'
when age > 81 then '>81'
END as age_group
FROM(
SELECT YEAR(current_time()) - Year(DateBorn) AS age
FROM custs
WHERE FDID = 'ANGL01'
) as custs2
GROUP BY age_group
When i ran this query, it worked fine, except that there were 2013 null results. It turns out that there are 2 data formats in the column.
The first on is just the year: 'yyyy'
The second on includes the day and month: 'dd/mm/yyyy'
How can I modify this query to take both data formats into account?
Ideally you should store dates using the DATE data type.
Given your current schema, assuming the dates are always either in yyyy or dd/mm/yyyy format then the year will always be the 4 rightmost characters, so you can use RIGHT(DateBorn,4), like this:
SELECT
COUNT(*),
CASE
when age < 60 THEN '<60'
when age >= 61 AND age <= 65 then '61-65'
when age >= 66 AND age <= 70 then '66-70'
when age >= 71 AND age <= 75 then '71-75'
when age >= 76 AND age <= 80 then '76-80'
when age > 81 then '>81'
END as age_group
FROM(
SELECT YEAR(current_date()) - CAST(RIGHT(DateBorn,4) AS UNSIGNED) AS age
FROM custs
WHERE FDID = 'ANGL01'
) as custs2
GROUP BY age_group
You should check for values that don't match your expected date formats. A query like this will give you a sample of non-conformant rows:
select DateBorn
from custs
where DateBorn not regexp '^[0-9][0-9][0-9][0-9]$'
and DateBorn not regexp '^[0-3][0-9]\/[0-1][0-9]\/[0-9][0-9][0-9][0-9]$'
limit 25
How about MySQL's STR_TO_DATE?
SELECT STR_TO_DATE(DATE_FORMAT(YourField, '%d/%m/%Y'),'%Y')...
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
Using this you can manipulate other occurrences. I have inherited legacy data you cannot change, so this function will accommodate everything you can mask, if your data is fairly consistent.
I may have it backwards. Try this, if needed.
SELECT date_format( str_to_date( dt3, '%m-%d-%Y' ) , '%m/%d/%Y' ) AS my_date FROM dt_tb3
http://www.plus2net.com/sql_tutorial/date-string.php
Assuming that DateBorn is a text column, try this:
SELECT YEAR(now()) - Year(str_to_date(DateBorn,
CASE WHEN char_length(DateBorn) = 4
THEN '01/01/%Y'
ELSE '%d/%m/%Y'
END
)) AS age
current_time() is an alias for curtime() which returns HH:MM:SS. So YEAR(current_time()) may result in some odd results. You might want to try YEAR(NOW()) instead.
You would also want to use STR_TO_DATE(str,format) to parse your varchar as a datetime. (Of course, it is better to fix the schema than patch it like this) Make sure to update the format as you have it in your table.
SELECT
COUNT(*),
CASE
when age < 60 THEN '<60'
when age >= 61 AND age <= 65 then '61-65'
when age >= 66 AND age <= 70 then '66-70'
when age >= 71 AND age <= 75 then '71-75'
when age >= 76 AND age <= 80 then '76-80'
when age > 81 then '>81'
END as age_group
FROM(
SELECT YEAR(NOW()) - Year(str_to_date(DateBorn, '%d/%m/%Y')) AS age
FROM custs
WHERE FDID = 'ANGL01'
) as custs2
GROUP BY age_group

What SQL better for calculated members age? (MySQL MYISAM)

I'm trying to show my members age in profile page.
I found 2 SQL queries:
SELECT TIMESTAMPDIFF(YEAR, dob, CURDATE()) AS age FROM users
and
SELECT FLOOR(DATEDIFF(CURRENT_DATE(), dob) / 365)
What SQL query better?? (For performance, accurate etc.)
I am not sure how this will translate into mysql. But here is a T-SQL that can calculate age for a person, given their birth date and current date.
select case
when cast(getdate() as date) = cast(dateadd(year, (datediff(year, '1996-09-09', getdate())), '1996-09-09') as date)
then dateDiff(yyyy,'1996-09-09',dateadd(year, 0, getdate()))
else dateDiff(yyyy,'1996-09-09',dateadd(year, -1, getdate()))
end as MemberAge
go