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

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

Related

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.

Order users by days until birthday

I have a table with people and their birth dates. I want to SELECT them ordered by the "number of days until next birthday".
I have tried with the DAYOFYEAR() function:
SELECT id, DAYOFYEAR(datebirth)-DAYOFYEAR(NOW()) AS daystobd
FROM users ORDER BY daystobd;
But... I got negative daystobd if the birthday has passed this year. The intention is to have those listed at the end.
Any idea ?
EDIT: daystobd should reflect the real number of days until next birthday
NEW EDIT:
I managed to do it with UNION, but I think surely there is a more "elegant" way to do this.
SELECT id, DAYOFYEAR(datebirth)-DAYOFYEAR(CURDATE()) AS daystobd
FROM users WHERE DAYOFYEAR(datebirth)-DAYOFYEAR(CURDATE())>=0
UNION
SELECT id, 365+DAYOFYEAR(datebirth)-DAYOFYEAR(CURDATE()) AS daystobd
FROM users WHERE DAYOFYEAR(datebirth)-DAYOFYEAR(CURDATE())<0 ORDER BY daystobd
Compare MMDD of today and the user's birthday. Then build the next birthday accordingly with the current or next year.
SELECT
id,
next_birthday,
DATEDIFF(next_birthday, NOW()) AS daystobd
FROM
(
SELECT
id,
datebirth,
CASE WHEN DATE_FORMAT(datebirth, '%m%d') >= DATE_FORMAT(NOW(), '%m%d')
THEN CONCAT(EXTRACT(YEAR FROM NOW()), '-', DATE_FORMAT(datebirth, '%m-%d'))
ELSE CONCAT(EXTRACT(YEAR FROM NOW()) + 1, '-', DATE_FORMAT(datebirth, '%m-%d'))
END AS next_birthday
FROM users
) data
ORDER BY DATEDIFF(next_birthday, NOW());
Give them a weight if below 0
ORDER BY CASE WHEN datstobd<0 THEN 1 ELSE 0 END,daystobd

MySQL query to Count Number of Users in Age Group

I am calculating the age of my users in MySQL and I am running into a little problem. I am able to successfully calculate the age of each user, however, when I try to count the number of users who are part of each age group, that is when I run into trouble. Here is my query:
SELECT COUNT(user_id) AS "Number of Users",
YEAR(CURDATE()) -
YEAR(STR_TO_DATE(birth_date, '%m/%d/%Y')) -
(RIGHT(CURDATE(), 5) < RIGHT(STR_TO_DATE(birth_date, '%m/%d/%Y'), 5))
AS Age
FROM user
GROUP BY Age
I feel like I am close, it just is not working for me. How would I count the number of users in each age group?
You need a subquery to access calculated column aliased Age in Group By clause
SELECT Age,COUNT(user_id) AS "Number of Users"
FROM
(
SELECT userid,
YEAR(CURDATE()) -
YEAR(STR_TO_DATE(birth_date, '%m/%d/%Y')) -
(RIGHT(CURDATE(), 5) < RIGHT(STR_TO_DATE(birth_date, '%m/%d/%Y'), 5))
AS Age
FROM user
) as Z
GROUP BY Age

Selecting age groups using SQL

This is a follow-up question on Get age from the birthday field with type date using SQL. I have a date field in a MySQL database for the birthday of a user and get the age using this query:
SELECT
ROUND(DATEDIFF(
Cast((SELECT NOW()) as Date),
Cast(birthday as Date)
) / 365, 0) as age
FROM member
Now, I need to select the number of people in different age groups. For example, I need to know how many people are in the age group 13-17, 18-21, 22-25, 26-35, 36-50, 51-MAX.
Is that possible using MySQL?
I have thought of UNIONs, like this:
SELECT
ROUND(DATEDIFF(
Cast((SELECT NOW()) as Date),
Cast(birthday as Date)
) / 365, 0) as age,
1 as agegroup
FROM member WHERE age >=13 AND age <=17
UNION
SELECT
ROUND(DATEDIFF(
Cast((SELECT NOW()) as Date),
Cast(birthday as Date)
) / 365, 0) as age
2 as agegroup
FROM member WHERE age >=18 AND age <=21
But that would be long and ugly. There must be a better way!
select AgeGroup
, count(*)
from (
select case
when age between 13 and 17 then 1
when age between 18 and 21 then 2
...
end as AgeGroup
from (
SELECT ROUND(DATEDIFF(Cast(NOW() as Date),
Cast(birthday as Date)) / 365, 0) as age
FROM YourTable
) as SubQueryAlias
) as SubQueryAlias2
group by
AgeGroup
Another possible solution:-
SELECT AgeRange.MinAge, AgeRange.MaxAge, COUNT(*)
FROM
(
SELECT 13 AS MinAge, 17 AS MaxAge
UNION SELECT 18, 21
UNION SELECT 22, 25
UNION SELECT 26, 35
UNION SELECT 36, 50
UNION SELECT 51, 9999
) AgeRange
INNER JOIN YourTable
ON ROUND(DATEDIFF(CAST(NOW() as DATE), CAST(birthday as DATE)) / 365, 0) BETWEEN AgeRange.MinAge AND AgeRange.MaxAge
GROUP BY AgeRange.MinAge, AgeRange.MaxAge
Possibly easier to expand if needs be, or to move to using date ranges from a table (so the resulting report could be updated by users easily if required).
If you had the age as a column in a table you would do it like this:
SELECT
SUM(CASE WHEN age < 10 THEN 1 ELSE 0 END) AS under10,
SUM(CASE WHEN 10<age AND age <19 THEN 1 ELSE 0 END) AS age10to19,
.
.
.
FROM table
There are likely to be minor changes because age isn't in its own column or if you want extra or different ranges. I'm sure you can work them out yourself!

How to select last one week data from today's date

How to select week data (more precisely, last 7 days data) from the current date in the fastest way as I have millions or rows in the table. I have a time stamp of created_date in sql table.
I have tried this
SELECT Created_Date
FROM Table_Name
WHERE Created_Date >= DATEADD(day,-7, GETDATE())
I have two question:
Is this query is correct?
Is this is the fastest way to get the last seven day data from a table having millions of rows ?
Yes, the syntax is accurate and it should be fine.
Here is the SQL Fiddle Demo I created for your particular case
create table sample2
(
id int primary key,
created_date date,
data varchar(10)
)
insert into sample2 values (1,'2012-01-01','testing');
And here is how to select the data
SELECT Created_Date
FROM sample2
WHERE Created_Date >= DATEADD(day,-11117, GETDATE())
to select records for the last 7 days
SELECT * FROM [TableName]
WHERE Created_Date >= DATEADD(day, -7, GETDATE())
to select records for the current week
SET DATEFIRST 1 -- Define beginning of week as Monday
SELECT * FROM [TableName]
WHERE CreatedDate >= DATEADD(day, 1 - DATEPART(WEEKDAY, GETDATE()), CONVERT(DATE, GETDATE()))
AND CreatedDate < DATEADD(day, 8 - DATEPART(WEEKDAY, GETDATE()), CONVERT(DATE, GETDATE()))
if you want to select records for last week instead of the last 7 days
SET DATEFIRST 1 -- Define beginning of week as Monday
SELECT * FROM [TableName]
WHERE CreatedDate >= DATEADD(day, -(DATEPART(WEEKDAY, GETDATE()) + 6), CONVERT(DATE, GETDATE()))
AND CreatedDate < DATEADD(day, 1 - DATEPART(WEEKDAY, GETDATE()), CONVERT(DATE, GETDATE()))
The query is correct
2A. As far as last seven days have much less rows than whole table an index can help
2B. If you are interested only in Created_Date you can try using some group by and count, it should help with the result set size