I'm trying to sort out a result set that gives the 5 closest users sorted by upcoming birthday. This works perfectly until leap years comes into play. For example:
The top result is a birth at 1987 and the lower is from 1988. u_birth is stored as yyyy-mm-dd. Is there a simple way to sort this problem without having to rewrite the entire query?
SELECT u_birth, IF( DAYOFYEAR( u_birth ) >= DAYOFYEAR( NOW() ),
DAYOFYEAR( u_birth ) - DAYOFYEAR( NOW() ),
DAYOFYEAR( u_birth ) - DAYOFYEAR( NOW() ) +
DAYOFYEAR( CONCAT( YEAR( NOW() ), '-12-31' ) )
)
AS distance
FROM (blog_users)
WHERE `s_agehide` = 0
ORDER BY distance ASC
LIMIT 5
This query is taken and modified from the mysql manual: http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#c7489
There's obviously a problem if your algorithm depends on the year of birth of the person. To workaround this, first find each person's next birthday after the current date, then calculate the difference between that date and now.
SELECT u_birth, DATEDIFF(next_birthday, NOW()) AS distance FROM (
SELECT *, ADDDATE(birthday, INTERVAL birthday < DATE(NOW()) YEAR) AS next_birthday
FROM (
SELECT *, ADDDATE(u_birth, INTERVAL YEAR(NOW()) - YEAR(u_birth) YEAR) AS birthday
FROM blog_users
WHERE s_agehide = 0
) AS T1
) AS T2
ORDER BY distance ASC
LIMIT 5
Results:
'1992-02-29', 20
'1993-03-01', 21
'1987-05-15', 96
'1988-05-15', 96
'1988-09-18', 222
Test data:
CREATE TABLE blog_users (u_birth NVARCHAR(100) NOT NULL, s_agehide INT NOT NULL);
INSERT INTO blog_users (u_birth, s_agehide) VALUES
('1987-05-15', 0),
('1988-05-15', 0),
('1988-09-20', 0),
('2000-01-02', 0),
('2000-01-03', 1),
('1988-09-19', 0),
('1988-09-18', 0),
('1992-02-29', 0),
('1993-03-01', 0);
Note that someone born on a leap day is assumed to have a birthday of 28th February on a non-leap year.
Also, your query doesn't include the user id of the user. You probably want to add this too, I'd imagine.
SELECT
CONCAT(
YEAR(CURRENT_DATE()),
'-',
DATE_FORMAT((birthDate),
'%m-%d'
)
),
fullName
FROM
employees
WHERE
birthDate != 0
AND(
CONCAT(
YEAR(CURRENT_DATE())+ 1,
'-',
DATE_FORMAT((birthDate),
'%m-%d'
)
)BETWEEN CURRENT_DATE()
AND DATE_ADD(
CURRENT_DATE(),
INTERVAL 21 DAY
)
OR CONCAT(
YEAR(CURRENT_DATE()),
'-',
DATE_FORMAT((birthDate),
'%m-%d'
)
)BETWEEN CURRENT_DATE()
AND DATE_ADD(
CURRENT_DATE(),
INTERVAL 21 DAY
)
)
ps: birthDate is the column where i stored the date of birth of the employees. employees is the table name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With