Как рассчитать возраст (в годах) на основе даты рождения и getDate()
У меня есть таблица с перечислением людей вместе с их датой рождения (в настоящее время nvarchar (25))
Как я могу преобразовать это в дату, а затем вычислить их возраст в годах?
Мои данные выглядят следующим образом
ID Name DOB
1 John 1992-01-09 00:00:00
2 Sally 1959-05-20 00:00:00
Я бы хотел:
ID Name AGE DOB
1 John 17 1992-01-09 00:00:00
2 Sally 50 1959-05-20 00:00:00
Ответы
Ответ 1
Существуют проблемы с високосным годом/днями и следующий метод, см. обновление ниже:
попробуйте следующее:
DECLARE @dob datetime
SET @dob='1992-01-09 00:00:00'
SELECT DATEDIFF(hour,@dob,GETDATE())/8766.0 AS AgeYearsDecimal
,CONVERT(int,ROUND(DATEDIFF(hour,@dob,GETDATE())/8766.0,0)) AS AgeYearsIntRound
,DATEDIFF(hour,@dob,GETDATE())/8766 AS AgeYearsIntTrunc
ВЫВОД:
AgeYearsDecimal AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054 18 17
(1 row(s) affected)
ОБНОВЛЕНИЕ приведены несколько более точных методов:
ЛУЧШИЙ МЕТОД ЗА ГОДЫ В INT
DECLARE @Now datetime, @Dob datetime
SELECT @Now='1990-05-05', @Dob='1980-05-05' --results in 10
--SELECT @Now='1990-05-04', @Dob='1980-05-05' --results in 9
--SELECT @Now='1989-05-06', @Dob='1980-05-05' --results in 9
--SELECT @Now='1990-05-06', @Dob='1980-05-05' --results in 10
--SELECT @Now='1990-12-06', @Dob='1980-05-05' --results in 10
--SELECT @Now='1991-05-04', @Dob='1980-05-05' --results in 10
SELECT
(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000 AS AgeIntYears
вы можете изменить выше 10000
на 10000.0
и получить десятичные числа, но это будет не так точно, как метод ниже.
ЛУЧШИЙ МЕТОД ЗА ГОДЫ В ДЕЦИМАЛЕ
DECLARE @Now datetime, @Dob datetime
SELECT @Now='1990-05-05', @Dob='1980-05-05' --results in 10.000000000000
--SELECT @Now='1990-05-04', @Dob='1980-05-05' --results in 9.997260273973
--SELECT @Now='1989-05-06', @Dob='1980-05-05' --results in 9.002739726027
--SELECT @Now='1990-05-06', @Dob='1980-05-05' --results in 10.002739726027
--SELECT @Now='1990-12-06', @Dob='1980-05-05' --results in 10.589041095890
--SELECT @Now='1991-05-04', @Dob='1980-05-05' --results in 10.997260273973
SELECT 1.0* DateDiff(yy,@Dob,@Now)
+CASE
WHEN @Now >= DATEFROMPARTS(DATEPART(yyyy,@Now),DATEPART(m,@Dob),DATEPART(d,@Dob)) THEN --birthday has happened for the @now year, so add some portion onto the year difference
( 1.0 --force automatic conversions from int to decimal
* DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),DATEPART(m,@Dob),DATEPART(d,@Dob)),@Now) --number of days difference between the @Now year birthday and the @Now day
/ DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),1,1),DATEFROMPARTS(DATEPART(yyyy,@Now)+1,1,1)) --number of days in the @Now year
)
ELSE --birthday has not been reached for the last year, so remove some portion of the year difference
-1 --remove this fractional difference onto the age
* ( -1.0 --force automatic conversions from int to decimal
* DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),DATEPART(m,@Dob),DATEPART(d,@Dob)),@Now) --number of days difference between the @Now year birthday and the @Now day
/ DATEDIFF(day,DATEFROMPARTS(DATEPART(yyyy,@Now),1,1),DATEFROMPARTS(DATEPART(yyyy,@Now)+1,1,1)) --number of days in the @Now year
)
END AS AgeYearsDecimal
Ответ 2
Надо бросить это. Если вы конвертируете дату с использованием стиля 112 (yyyymmdd) в число, вы можете использовать вычисления, подобные этому...
(yyyyMMdd - yyyyMMdd)/10000 = разница в полных годах
declare @as_of datetime, @bday datetime;
select @as_of = '2009/10/15', @bday = '1980/4/20'
select
Convert(Char(8),@as_of,112),
Convert(Char(8),@bday,112),
0 + Convert(Char(8),@as_of,112) - Convert(Char(8),@bday,112),
(0 + Convert(Char(8),@as_of,112) - Convert(Char(8),@bday,112)) / 10000
Выход
20091015 19800420 290595 29
Ответ 3
Я использовал этот запрос в нашем производственном коде в течение почти 10 лет:
SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
Ответ 4
Таким образом, многие из вышеперечисленных решений неверны. DateDiff (yy, @Dob, @PassedDate) не учитывает месяц и день обеих дат. Также, принимая детали дротика и сравнивая, работает только в том случае, если они правильно упорядочены.
СЛЕДУЮЩИЙ КОД РАБОТЫ И ОЧЕНЬ ПРОСТО:
create function [dbo].[AgeAtDate](
@DOB datetime,
@PassedDate datetime
)
returns int
with SCHEMABINDING
as
begin
declare @iMonthDayDob int
declare @iMonthDayPassedDate int
select @iMonthDayDob = CAST(datepart (mm,@DOB) * 100 + datepart (dd,@DOB) AS int)
select @iMonthDayPassedDate = CAST(datepart (mm,@PassedDate) * 100 + datepart (dd,@PassedDate) AS int)
return DateDiff(yy,@DOB, @PassedDate)
- CASE WHEN @iMonthDayDob <= @iMonthDayPassedDate
THEN 0
ELSE 1
END
End
Ответ 5
Вам нужно рассмотреть способ командных раундов датифф.
SELECT CASE WHEN dateadd(year, datediff (year, DOB, getdate()), DOB) > getdate()
THEN datediff(year, DOB, getdate()) - 1
ELSE datediff(year, DOB, getdate())
END as Age
FROM <table>
Что я адаптировал из здесь
Ответ 6
РЕДАКТИРОВАТЬ: ЭТО ОТВЕТ НЕПРАВИЛЬНО. Я оставляю это здесь как предупреждение для всех, кто хотел использовать dayofyear
, с дальнейшим редактированием в конце.
Если, как и я, вы не хотите делиться дробными днями или рисковать ошибками округления/високосного года, я приветствую комментарий @Bacon Bits в сообщении выше fooobar.com/questions/48610/... где он говорит:
Если мы говорим о человеческом возрасте, вы должны рассчитать его так люди вычисляют возраст. Это не имеет никакого отношения к тому, как быстро земля движения и все, что связано с календарем. Каждый раз месяц и день, как дата рождения, вы увеличиваете возраст на 1. Это означает, что следующее наиболее точное, поскольку оно отражает то, что люди имеют в виду, когда говорят "возраст".
Затем он предлагает:
DATEDIFF(yy, @date, GETDATE()) -
CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE()))
THEN 1 ELSE 0 END
Здесь есть несколько советов, связанных с сравнением месяца и дня (и некоторые из них ошибаются, не позволяя OR
) правильно здесь!). Но никто не предложил dayofyear
, который кажется таким простым и намного короче. Я предлагаю:
DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
[Примечание: нигде в SQL BOL/MSDN то, что DATEPART(dayofyear, ...)
возвращает фактически документированное! Я понимаю, что это число в диапазоне 1--366; самое главное, он не изменяется по языку в соответствии с DATEPART(weekday, ...)
и SET DATEFIRST
.]
РЕДАКТИРОВАТЬ: Почему dayofyear
идет не так: как пользователь @AeroX прокомментировал, если дата рождения/начала была после февраля в течение не високосного года, возраст увеличивается на один день раньше, текущая/конечная дата - это високосный год, например '2015-05-26'
, '2016-05-25'
дает возраст 1, когда он все равно равен 0. Сравнение dayofyear
в разные годы явно опасно. Поэтому использование MONTH()
и DAY()
необходимо в конце концов.
Ответ 7
Поскольку нет простого ответа, который всегда дает правильный возраст, вот что я придумал.
SELECT DATEDIFF(YY, DateOfBirth, GETDATE()) -
CASE WHEN RIGHT(CONVERT(VARCHAR(6), GETDATE(), 12), 4) >=
RIGHT(CONVERT(VARCHAR(6), DateOfBirth, 12), 4)
THEN 0 ELSE 1 END AS AGE
Это означает разницу в году между датой рождения и текущей датой. Затем он вычитает год, если дата рождения еще не прошла.
Точно все время - независимо от високосных лет или как близко к дате рождения.
Лучше всего - никакой функции.
Ответ 8
Как насчет:
DECLARE @DOB datetime
SET @DOB='19851125'
SELECT Datepart(yy,convert(date,GETDATE())[email protected])-1900
Разве это не могло бы избежать всех проблем округления, усечения и постановки вопроса?
Ответ 9
Просто проверьте, возможен ли ответ ниже.
DECLARE @BirthDate DATE = '09/06/1979'
SELECT
(
YEAR(GETDATE()) - YEAR(@BirthDate) -
CASE WHEN (MONTH(GETDATE()) * 100) + DATEPART(dd, GETDATE()) >
(MONTH(@BirthDate) * 100) + DATEPART(dd, @BirthDate)
THEN 1
ELSE 0
END
)
Ответ 10
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
Ответ 11
DECLARE @DOB datetime
set @DOB ='11/25/1985'
select floor(
( cast(convert(varchar(8),getdate(),112) as int)-
cast(convert(varchar(8),@DOB,112) as int) ) / 10000
)
источник: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/
Ответ 12
Я считаю, что это похоже на другие, опубликованные здесь... но это решение сработало для примеров високосного года с 02/29/1976 по 03/01/2011, а также работало на случай в течение первого года.. like 07/04/2011 по 07/03/2012, который последний опубликовал о решении в течение високосного года, не работал в этом первом случае использования.
SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)
Найдено здесь.
Ответ 13
Я много думал и искал об этом, и у меня есть 3 решения, которые
- правильно рассчитать возраст
- являются короткими (в основном)
- (в основном) очень понятные.
Здесь приведены значения для тестирования:
DECLARE @NOW DATETIME = '2013-07-04 23:59:59'
DECLARE @DOB DATETIME = '1986-07-05'
Решение 1: Я нашел этот подход в одной js-библиотеке. Это мой любимый.
DATEDIFF(YY, @DOB, @NOW) -
CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END
Это фактически добавляет разницу в годах к DOB, и если она больше текущей, а затем вычитает один год. Просто так? Единственное, что разница в годах дублируется здесь.
Но если вам не нужно использовать его inline, вы можете написать его вот так:
DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW)
IF DATEADD(YY, @AGE, @DOB) > @NOW
SET @AGE = @AGE - 1
Решение 2:. Это я изначально скопировал из @bacon-bits. Это проще всего понять, но немного долго.
DATEDIFF(YY, @DOB, @NOW) -
CASE WHEN MONTH(@DOB) > MONTH(@NOW)
OR MONTH(@DOB) = MONTH(@NOW) AND DAY(@DOB) > DAY(@NOW)
THEN 1 ELSE 0 END
Он в основном вычисляет возраст, как мы, люди.
Решение 3: Мой друг реорганизовал это:
DATEDIFF(YY, @DOB, @NOW) -
CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))
Этот самый короткий, но наиболее трудный для понимания. 50
- это просто вес, поэтому разница в день важна только тогда, когда месяцы одинаковы. Функция SIGN
предназначена для преобразования любого значения, которое оно получает в -1, 0 или 1. CEILING(0.5 *
совпадает с Math.max(0, value)
, но в SQL нет такой вещи.
Ответ 14
Как насчет этого:
SET @Age = CAST(DATEDIFF(Year, @DOB, @Stamp) as int)
IF (CAST(DATEDIFF(DAY, DATEADD(Year, @Age, @DOB), @Stamp) as int) < 0)
SET @Age = @Age - 1
Ответ 15
Попробуйте это
DECLARE @date datetime, @tmpdate datetime, @years int, @months int, @days int
SELECT @date = '08/16/84'
SELECT @tmpdate = @date
SELECT @years = DATEDIFF(yy, @tmpdate, GETDATE()) - CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
SELECT @tmpdate = DATEADD(yy, @years, @tmpdate)
SELECT @months = DATEDIFF(m, @tmpdate, GETDATE()) - CASE WHEN DAY(@date) > DAY(GETDATE()) THEN 1 ELSE 0 END
SELECT @tmpdate = DATEADD(m, @months, @tmpdate)
SELECT @days = DATEDIFF(d, @tmpdate, GETDATE())
SELECT Convert(Varchar(Max),@years)+' Years '+ Convert(Varchar(max),@months) + ' Months '+Convert(Varchar(Max), @days)+'days'
Ответ 16
Попробуйте это решение:
declare @BirthDate datetime
declare @ToDate datetime
set @BirthDate = '1/3/1990'
set @ToDate = '1/2/2008'
select @BirthDate [Date of Birth], @ToDate [ToDate],(case when (DatePart(mm,@ToDate) < Datepart(mm,@BirthDate))
OR (DatePart(m,@ToDate) = Datepart(m,@BirthDate) AND DatePart(dd,@ToDate) < Datepart(dd,@BirthDate))
then (Datepart(yy, @ToDate) - Datepart(yy, @BirthDate) - 1)
else (Datepart(yy, @ToDate) - Datepart(yy, @BirthDate))end) Age
Ответ 17
Это будет правильно обрабатывать проблемы с днем рождения и округлением:
DECLARE @dob datetime
SET @dob='1992-01-09 00:00:00'
SELECT DATEDIFF(YEAR, '0:0', getdate()[email protected])
Ответ 18
Решение Ed Harper - это самый простой, который я нашел, который никогда не возвращает неправильный ответ, когда месяц и день двух дат равны 1 или менее дням. Я сделал небольшую модификацию для обработки отрицательных возрастов.
DECLARE @D1 AS DATETIME, @D2 AS DATETIME
SET @D2 = '2012-03-01 10:00:02'
SET @D1 = '2013-03-01 10:00:01'
SELECT
DATEDIFF(YEAR, @D1,@D2)
+
CASE
WHEN @D1<@D2 AND DATEADD(YEAR, DATEDIFF(YEAR,@D1, @D2), @D1) > @D2
THEN - 1
WHEN @D1>@D2 AND DATEADD(YEAR, DATEDIFF(YEAR,@D1, @D2), @D1) < @D2
THEN 1
ELSE 0
END AS AGE
Ответ 19
Ответ, помеченный как правильный, ближе к точности, но он терпит неудачу в следующем сценарии - где Год рождения - Високосный год и день после февральского месяца
declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
@DateofBirth datetime = CONVERT(datetime, '2/29/1948')
FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766)
ИЛИ
FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766
- Следующее решение дает мне более точные результаты.
FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END ))
Он работал практически во всех сценариях, учитывая високосный год, дату 29 фб и т.д.
Пожалуйста, исправьте меня, если у этой формулы есть лазейка.
Ответ 20
Declare @dob datetime
Declare @today datetime
Set @dob = '05/20/2000'
set @today = getdate()
select CASE
WHEN dateadd(year, datediff (year, @dob, @today), @dob) > @today
THEN datediff (year, @dob, @today) - 1
ELSE datediff (year, @dob, @today)
END as Age
Ответ 21
CREATE function dbo.AgeAtDate(
@DOB datetime,
@CompareDate datetime
)
returns INT
as
begin
return CASE WHEN @DOB is null
THEN
null
ELSE
DateDiff(yy,@DOB, @CompareDate)
- CASE WHEN datepart(mm,@CompareDate) > datepart(mm,@DOB) OR (datepart(mm,@CompareDate) = datepart(mm,@DOB) AND datepart(dd,@CompareDate) >= datepart(dd,@DOB))
THEN 0
ELSE 1
END
END
End
GO
Ответ 22
Вот как я вычисляю возраст с датой рождения и текущей датой.
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
Ответ 23
DECLARE @FromDate DATETIME = '1992-01-2623:59:59.000',
@ToDate DATETIME = '2016-08-10 00:00:00.000',
@Years INT, @Months INT, @Days INT, @tmpFromDate DATETIME
SET @Years = DATEDIFF(YEAR, @FromDate, @ToDate)
- (CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, @FromDate, @ToDate),
@FromDate) > @ToDate THEN 1 ELSE 0 END)
SET @tmpFromDate = DATEADD(YEAR, @Years , @FromDate)
SET @Months = DATEDIFF(MONTH, @tmpFromDate, @ToDate)
- (CASE WHEN DATEADD(MONTH,DATEDIFF(MONTH, @tmpFromDate, @ToDate),
@tmpFromDate) > @ToDate THEN 1 ELSE 0 END)
SET @tmpFromDate = DATEADD(MONTH, @Months , @tmpFromDate)
SET @Days = DATEDIFF(DAY, @tmpFromDate, @ToDate)
- (CASE WHEN DATEADD(DAY, DATEDIFF(DAY, @tmpFromDate, @ToDate),
@tmpFromDate) > @ToDate THEN 1 ELSE 0 END)
SELECT @FromDate FromDate, @ToDate ToDate,
@Years Years, @Months Months, @Days Days
Ответ 24
CASE WHEN datepart(MM, getdate()) < datepart(MM, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTH_DATE)) -1 )
ELSE
CASE WHEN datepart(MM, getdate()) = datepart(MM, BIRTHDATE)
THEN
CASE WHEN datepart(DD, getdate()) < datepart(DD, BIRTHDATE) THEN ((datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) -1 )
ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE))
END
ELSE (datepart(YYYY, getdate()) - datepart(YYYY, BIRTHDATE)) END
END
Ответ 25
Мы использовали что-то вроде этого, но затем, взяв средний возраст:
ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge
Обратите внимание, что ROUND находится снаружи, а не внутри. Это позволит AVG быть более точным, и мы ROUND только один раз. Быстрее и быстрее.
Ответ 26
select datediff(day,'1991-03-16',getdate()) \\for days,get date refers today date
select datediff(year,'1991-03-16',getdate()) \\for years
select datediff(month,'1991-03-16',getdate()) \\for month
Ответ 27
select DATEDIFF(yy,@DATE,GETDATE()) -
case when DATEPART(mm,GETDATE())*100+DATEPART(dd,GETDATE())>=
DATEPART(mm,@DATE)*100+DATEPART(dd,@DATE) THEN 0
ELSE 1 END
Ответ 28
SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int)
Ответ 29
вы должны сосчитать годы следующим образом: -
select cast(datediff(DAY, '2000-03-01 10:00:01', '2013-03-01 10:00:00') / (365.23076923074) as int) as 'Age'
это очень легко...
Ответ 30
вы должны использовать
выберите FLOOR (DATEDIFF (CURDATE(), DATE (DOB))/365.25) из table_name;
здесь CURDATE() использует текущую дату, которую вы можете присвоить своей дате в формате "yyyy-mm-dd"
ДАТА (DOB) извлекает yyyy-mm-dd year из вашего столбца, который находится в формате DATETIME
здесь DOB - это ваше имя столбца (но вы должны изменить таблицу, чтобы изменить тип данных, который должен быть DATETIME в вашем случае, который является nvarchar)
Заметка-
этот запрос используется в mysql
этот возраст возврата в течение всего года