In a SQL Server database, I record people\'s date of birth. Is there an straight-forward method of working out the person\'s age on a given date using SQL only?
Usi
SELECT Pname, DOB, DATEDIFF(YEAR, DOB, GETDATE()) AS Age
FROM tablename
This is more concise and a bit faster than the answers provided, and completely accurate:
datediff(year,DateOfBirth,getdate()-datepart(dy,DateOfBirth)+1)
There is another way that is a bit simpler:
Select CAST(DATEDIFF(hh, [birthdate], GETDATE()) / 8766 AS int) AS Age
Because the rounding here is very granular, this is almost perfectly accurate. The exceptions are so convoluted that they are almost humorous: every fourth year the age returned will be one year too young if we A) ask for the age before 6:00 AM, B) on the person's birthday and C) their birthday is after February 28th. In my setting, this is a perfectly acceptable compromise.
I hope this one is perfect provided you accept the algorithm that a leap-baby turns a year older on successive February 29th's, or March 1's on non-leap years. @DOB must contain a date within a few centuries of now, @AsOf must contain a similar date >= @DOB:
SET @Age = YEAR(@AsOf) - YEAR(@DOB) - 1
IF MONTH(@AsOf) * 100 + DAY(@AsOf) >= MONTH(@DOB) * 100 + DAY(@DOB)
SET @Age = @Age + 1
I'd REALLY REALLY appreciate any testing and comments as I haven't found a way yet to break it... yet.
Added - 1/31/2014: This one seems to work perfectly too even though at first glance it looks too crude:
SET @Age = FLOOR(DATEDIFF(dd,@DOB,@CompareDate)/365.25)
Pop these in a function and here's a test script:
SELECT dbo.fnGetAge('2/27/2008', '2/27/2012')
SELECT dbo.fnGetAge('2/27/2008', '2/28/2012')
SELECT dbo.fnGetAge('2/27/2008', '2/29/2012')
SELECT dbo.fnGetAge('2/27/2008', '3/1/2012')
-- 4 4 4 4
SELECT dbo.fnGetAge('2/28/2008', '2/27/2012')
SELECT dbo.fnGetAge('2/28/2008', '2/28/2012')
SELECT dbo.fnGetAge('2/28/2008', '2/29/2012')
SELECT dbo.fnGetAge('2/28/2008', '3/1/2012')
-- 3 4 4 4
SELECT dbo.fnGetAge('2/29/2008', '2/27/2012')
SELECT dbo.fnGetAge('2/29/2008', '2/28/2012')
SELECT dbo.fnGetAge('2/29/2008', '2/29/2012')
SELECT dbo.fnGetAge('2/29/2008', '3/1/2012')
-- 3 3 4 4
SELECT dbo.fnGetAge('3/1/2008', '2/27/2012')
SELECT dbo.fnGetAge('3/1/2008', '2/28/2012')
SELECT dbo.fnGetAge('3/1/2008', '2/29/2012')
SELECT dbo.fnGetAge('3/1/2008', '3/1/2012')
-- 3 3 3 4
SELECT dbo.fnGetAge('3/1/2007', '2/27/2012')
SELECT dbo.fnGetAge('3/1/2007', '2/28/2012')
SELECT dbo.fnGetAge('3/1/2007', '2/29/2012')
SELECT dbo.fnGetAge('3/1/2007', '3/1/2012')
-- 4 4 4 5
SELECT dbo.fnGetAge('3/1/2007', '2/27/2013')
SELECT dbo.fnGetAge('3/1/2007', '2/28/2013')
SELECT dbo.fnGetAge('3/1/2007', '3/1/2013')
SELECT dbo.fnGetAge('2/27/2007', '2/28/2013')
SELECT dbo.fnGetAge('2/28/2007', '2/28/2014')
-- 5 5 6 6 7
Cheers
PS: You can probably tweak the February 29 decision to being a day earlier if that floats your boat.
FWIW, Age can be computed in a straightforward manner without resorting to hacks (not that there's anything wrong with hacks!):
CREATE FUNCTION Age (@BirthDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE @AgeOnBirthdayThisYear INT
DECLARE @BirthdayThisYear DATETIME
SET @AgeOnBirthdayThisYear = DATEDIFF(year, @BirthDate, GETDATE())
SET @BirthdayThisYear = DATEADD(year, @AgeOnBirthdayThisYear, @BirthDate)
RETURN
@AgeOnBirthdayThisYear
- CASE WHEN @BirthdayThisYear > GETDATE() THEN 1 ELSE 0 END
END
This solution show how in one query without variables
SELECT DATEDIFF(YY, birthdate, GETDATE()) - CASE WHEN( (MONTH(birthdate)*100 + DAY(birthdate)) > (MONTH(GETDATE())*100 + DAY(GETDATE())) ) THEN 1 ELSE 0 END