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.
Related
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
I'm attempting to write a query that finds the user's work anniversary for the current month and considers a leap year as well (don't get an idea how to manage within the query)
Table "emp_detail":
emp_no
join_date
1
2002-06-10
2
2022-06-25
3
2020-02-29
4
2002-02-15
5
2011-02-01
So far I have tried the below query:
SELECT no,
join_date
CASE WHEN DATEADD(YY,DATEDIFF(yy,join_date,GETDATE()),join_date) < GETDATE()
THEN DATEDIFF(yy,join_date,GETDATE())
ELSE DATEDIFF(yy,join_date,GETDATE()) - 1
END AS 'anniversary'
FROM emp_detail
WHERE 'status' = 'active'
HAVING MONTH(join_date) = 06/07/08 -- ...so on
EDIT:
Expected output:
For FEBRUARY month current year 2022
emp_no
join_date
anniversary_date
3
2020-02-29
2022-02-28 (Here, want get 29 Feb 2020 leap year record with non leap year 2022)
4
2002-02-15
2022-02-15
5
2011-02-01
2022-02-01
Looking for a way to display employees with anniversary dates coming up at the start of the current month considering the leap year.
Am I going in the right direction? Any help would be great.
Most (all?) SQL engines already handle year arithmetic involving leap days the way you want: folding the leap day to the final day of February.
So, computing the employee's join_date + INTERVAL x YEAR will handle '2020-02-29' correctly. To compute that interval in MySQL/MariaDB for the current year, you may use TIMESTAMPDIFF compute the difference between EXTRACTed years yourself:
SELECT emp_no,
join_date,
join_date +
INTERVAL (EXTRACT(YEAR FROM CURDATE()) -
EXTRACT(YEAR FROM join_date)) YEAR
AS "anniversary_date_this_year",
....
You can split your problem into two steps:
filtering your "join_date" values using the current month
changing the year to your "join_date"
getting the minimum value between your updated "join_date" and the last day for that date (>> this will handle leap years kinda efficiently wrt other solutions that attempt to check for specific years every time)
WITH cte AS (
SELECT emp_no,
join_date,
STR_TO_DATE(CONCAT_WS('-',
YEAR (CURRENT_DATE()),
MONTH(join_date ),
DAY (join_date )),
'%Y-%m-%d') AS join_date_now
FROM tab
WHERE MONTH(join_date) = MONTH(CURRENT_DATE())
AND YEAR(join_date) < YEAR(CURRENT_DATE())
)
SELECT emp_no,
join_date,
LEAST(join_date_now, LAST_DAY(join_date_now)) AS anniversary_date
FROM cte
Check the demo here
Note: in the demo, since you want to look at February months and we are in July, the WHERE clause will contain an additional -5 while checking the month.
You can make use of extract function in MySQL
select * from emp_detail where extract( month from (select now())) = extract( month from join_date) and extract( year from (select now())) != extract( year from join_date);
The above query will display all employees whose work anniversary is in the current month.
For the below table:
The above query will display the following rows.
The following query also considers leap year.
If the employee has joined on Feb-29 in a leap year and the current year is a non-leap year, then the query displays Anniversary Date as 'currentYear-Feb-28'
If the employee has joined on Feb-29 in a leap year and the current year is also a leap year, then the query displays Anniversay Date as 'currentYear-Feb-29'
select empId ,
case
when ( ( extract(year from (select now()))%4 = 0 and extract(year from (select now()))%100 != 0 ) or extract(year from (select now())) % 400 = 0 ) then
cast( concat( extract(year from (select now())), '-', extract( month from join_date),'-', extract( day from join_date) ) as date)
when ( ( (extract(year from join_date) % 4 = 0 and extract(year from join_date)%100 != 0) or extract( year from join_date)%400 = 0) and extract(month from join_date) =2
and extract(day from join_date) = 29 ) then
cast( concat( cast( extract(year from (select now())) as nchar), '-02-28') as date)
else cast( concat( extract(year from (select now())), '-', extract( month from join_date),'-', extract( day from join_date) ) as date)
end as AnniversaryDate
from emp_detail
where extract(year from join_date) != extract(year from (select now()));
Emp_detail data
For this data the query will show the following rows
Further if you want to filter the date to current month only, you can make use of extract function.
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.
I am trying to make simple MySQL query to display upcoming birthdays using below query. How to exclude/remove previous(yesterday) day from showing.
CREATE TABLE users (
name VARCHAR(100),
birthday DATE
);
INSERT INTO users (name, birthday) VALUES
('kostas', '1983-10-08'),
('kostas', '1983-10-11'),
('yannis', '1979-10-13'),
('natalia', '1980-10-15'),
('kostas', '1983-10-12'),
('Moskas', '1978-10-14'),
('Rasman', '1978-10-13'),
('natalia', '1980-10-18'),
('natalia', '1980-10-16');
Query:
SELECT *
FROM
users
WHERE
birthday != '' AND ABS(DAY(CURDATE()) - DAY(birthday)) < 2
ORDER BY
DAY(birthday)
Demo: sqlfiddle
You have to use BETWEEN instead of ABS. The absolute value do not return what you want, the between 0 and "days before the birthday" (2) is the right way to get days until birthday.
You also have to use DAYOFYEAR instead of DAY and you have to reverse the order of the subtraction terms DAYOFYEAR(birthday) - DAYOFYEAR(CURDATE())
To workaround leap years birthdays, as suggested here, birthday year should be converted to current year with:
DAYOFYEAR(DATE_ADD(e.birthdate, INTERVAL (YEAR(NOW()) - YEAR(birthday)) YEAR))
The final SQL is:
SELECT *
FROM
users
WHERE
birthday != '' AND (DAYOFYEAR(DATE_ADD(birthday, INTERVAL (YEAR(NOW()) - YEAR(birthday)) YEAR))-DAYOFYEAR(CURDATE())) between 0 and 2
ORDER BY
DAY(birthday)
I'd do it this way:
Transfer the birthdays to the current year and then define the datediff you want:
SELECT *,
DATEDIFF(str_to_date(CONCAT(YEAR(curdate()), '-', MONTH(birthday), '-', DAY(birthday)), '%Y-%m-%d'), curdate()) AS `days until birthday`
FROM users
WHERE DATEDIFF(str_to_date(CONCAT(YEAR(curdate()), '-', MONTH(birthday), '-', DAY(birthday)), '%Y-%m-%d'), curdate()) BETWEEN 1 AND 5 ;
I have used this previously, hope it will help others.
SELECT name, birthday, DATE_ADD(birthday, INTERVAL IF(DAYOFYEAR(birthday) >= DAYOFYEAR(CURDATE()), YEAR(CURDATE())-YEAR(birthday), YEAR(CURDATE())-YEAR(birthday)+1) YEAR ) AS next_birthday
FROM users
WHERE birthday!= '' AND disabled = '0'
HAVING next_birthday BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 3 DAY)
ORDER BY next_birthday
Is there a cleaner/shorter/more readable way to add a WHERE statement for a query with the current day and month combo.
SELECT id, name, dob, (YEAR(NOW()) - YEAR(dob)) AS age
FROM people
WHERE MONTH(dob) = MONTH(NOW()) AND DAY(dob) = DAY(NOW())
For example;
WHERE dob = THISDAY()
People born on Feb. 29th generally celebrate their birthday on the 60th day, regardless of the calendar date (May 1st on non-leap years).
While not shorter, this method doesn't leave out those born on Feb. 29:
SELECT id, name, dob, (YEAR(NOW()) - YEAR(dob)) AS age
FROM people
WHERE DAYOFYEAR(curdate()) =
DAYOFYEAR(DATE_ADD(dob, INTERVAL (YEAR(NOW()) - YEAR(dob)) YEAR))
Leap years are the reason there is no simple method like DAYOFYEAR(curdate()) = DAYOFYEAR(dob).