sql-server - entre - cantidad de años en sql
Cómo calcular la edad(en años) según la fecha de nacimiento y getDate() (30)
Simplemente verifique si la respuesta a continuación es factible.
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
)
Tengo una tabla que enumera personas junto con su fecha de nacimiento (actualmente un nvarchar (25))
¿Cómo puedo convertir eso en una fecha y luego calcular su edad en años?
Mi información se ve de la siguiente manera
ID Name DOB
1 John 1992-01-09 00:00:00
2 Sally 1959-05-20 00:00:00
Me gustaría ver:
ID Name AGE DOB
1 John 17 1992-01-09 00:00:00
2 Sally 50 1959-05-20 00:00:00
Así es como calculo la edad dada una fecha de nacimiento y una fecha actual.
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
Como no hay una respuesta simple que siempre dé la edad correcta, esto es lo que se me ocurrió.
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
Esto obtiene la diferencia anual entre la fecha de nacimiento y la fecha actual. Luego resta un año si la fecha de nacimiento aún no ha pasado.
Preciso todo el tiempo, independientemente de los años bisiestos o lo cerca que esté de la fecha de nacimiento.
Lo mejor de todo: sin función.
Creo que esto es similar a otros publicados aquí ... pero esta solución funcionó para los ejemplos del año bisiesto 29/02/1976 al 01/03/2011 y también funcionó para el caso durante el primer año ... como 07/04 / 2011 al 07/03/2012 que el último publicado sobre la solución del año bisiesto no funcionó para ese caso de uso del primer año.
SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)
Encontrado here .
Debe considerar la forma en que redondea el comando datediff.
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>
Que he adaptado desde here
Deberías usar
seleccione FLOOR (DATEDIFF (CURDATE (), DATE (DOB)) / 365.25) de table_name;
aquí CURDATE () usa la fecha actual, puede dar fecha propia en formato ''aaaa-mm-dd'' FECHA (DOB) extraer año yyyy-mm-dd de su columna que está en formato DATETIME aquí DOB es su nombre de columna (pero debe alter table para modificar el tipo de datos para que sea DATETIME en su caso, que es nvarchar) Nota: esta consulta se usa en mysql esta edad de retorno en todo el año
Esto solucionará correctamente los problemas con el cumpleaños y el redondeo:
DECLARE @dob datetime
SET @dob=''1992-01-09 00:00:00''
SELECT DATEDIFF(YEAR, ''0:0'', getdate()-@dob)
Hay problemas con el año / día bisiesto y el siguiente método, consulte la actualización a continuación:
prueba esto:
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
SALIDA:
AgeYearsDecimal AgeYearsIntRound AgeYearsIntTrunc --------------------------------------- ---------------- ---------------- 17.767054 18 17 (1 row(s) affected)
ACTUALIZAR aquí hay algunos métodos más precisos:
MEJOR MÉTODO PARA AÑOS EN 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
puede cambiar los 10000
a 10000.0
y obtener decimales, pero no será tan preciso como el método a continuación.
MEJOR MÉTODO PARA AÑOS EN DECIMAL
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
He pensado mucho y buscado sobre esto y tengo 3 soluciones que
- calcular la edad correctamente
- son cortos (principalmente)
- son (en su mayoría) muy comprensibles.
Aquí están los valores de prueba:
DECLARE @NOW DATETIME = ''2013-07-04 23:59:59''
DECLARE @DOB DATETIME = ''1986-07-05''
Solución 1: Encontré este enfoque en una biblioteca js. Es mi favorito.
DATEDIFF(YY, @DOB, @NOW) -
CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END
De hecho, agrega diferencia en años a DOB y si es más grande que la fecha actual, resta un año. Simple ¿verdad? Lo único es que la diferencia en años se duplica aquí.
Pero si no necesita usarlo en línea, puede escribirlo así:
DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW)
IF DATEADD(YY, @AGE, @DOB) > @NOW
SET @AGE = @AGE - 1
Solución 2: Esta, originalmente copié de @ bacon-bits. Es el más fácil de entender, pero un poco largo.
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
Básicamente es calcular la edad como lo hacemos los humanos.
Solución 3: mi amigo lo refactoó en esto:
DATEDIFF(YY, @DOB, @NOW) -
CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))
Este es el más corto, pero es más difícil de entender. 50
es solo un peso, por lo que la diferencia de días solo es importante cuando los meses son iguales. SIGN
función SIGN
es para transformar cualquier valor que obtenga en -1, 0 o 1. CEILING(0.5 *
es lo mismo que Math.max(0, value)
pero no existe tal cosa en SQL.
La respuesta marcada como correcta está más cerca de la precisión, pero falla en el escenario siguiente, donde el año de nacimiento es el año bisiesto y el día posterior al mes de febrero.
declare @ReportStartDate datetime = CONVERT(datetime, ''1/1/2014''),
@DateofBirth datetime = CONVERT(datetime, ''2/29/1948'')
FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766)
O
FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766
- La siguiente solución me está dando resultados más precisos.
FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END ))
Funcionó en casi todos los escenarios, considerando año bisiesto, fecha como 29 feb, etc.
Por favor corrígeme si esta fórmula tiene alguna escapatoria.
La solución de Ed Harper es la más simple que he encontrado y que nunca arroja la respuesta incorrecta cuando el mes y el día de las dos fechas tienen 1 o menos días de diferencia. Hice una pequeña modificación para manejar las edades negativas.
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
Muchas de las soluciones anteriores son incorrectas DateDiff (yy, @ Dob, @PassedDate) no tendrá en cuenta el mes y el día de ambas fechas. También tomar las partes del dardo y comparar solo funciona si están ordenadas correctamente.
EL SIGUIENTE CÓDIGO FUNCIONA Y ES MUY SENCILLO:
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
Prueba esta solución:
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
Prueba esto
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''
Qué pasa:
DECLARE @DOB datetime
SET @DOB=''19851125''
SELECT Datepart(yy,convert(date,GETDATE())-@DOB)-1900
¿No evitaría eso todos esos problemas de redondeo, truncamiento y ataque?
Qué tal esto:
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
Tengo que tirar este por ahí. Si convert la fecha usando el estilo 112 (aaaammdd) a un número, puede usar un cálculo como este ...
(aaaaMMdd - aaaaMMdd) / 10000 = diferencia en años completos
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
salida
20091015 19800420 290595 29
Usamos algo así como aquí, pero luego tomamos la edad promedio:
ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge
Tenga en cuenta que la VUELTA está afuera en lugar de adentro. Esto permitirá que AVG sea más preciso y ROUND solo una vez. Haciéndolo más rápido también.
Utilicé esta consulta en nuestro código de producción durante casi 10 años:
SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
deberías contar años de la siguiente manera:
select cast(datediff(DAY, ''2000-03-01 10:00:01'', ''2013-03-01 10:00:00'') / (365.23076923074) as int) as ''Age''
es muy fácil...
EDITAR: ESTA RESPUESTA ES INCORRECTA. Lo dejo aquí como una advertencia para cualquier persona tentado de usar dayofyear
, con una edición adicional al final.
Si, como yo, no desea dividir por días fraccionarios ni arriesgarse a errores de redondeo / año bisiesto, aplaudo a @Bacon Bits al comentar en una publicación anterior https://.com/a/1572257/489865 donde dice:
Si hablamos de la edad humana, deberías calcularla de la misma manera que los humanos calculan la edad. No tiene nada que ver con qué tan rápido se mueve la tierra y todo lo que tiene que ver con el calendario. Cada vez que transcurre el mismo mes y día que la fecha de nacimiento, se aumenta la edad en 1. Esto significa que la siguiente es la más precisa porque refleja lo que los humanos quieren decir cuando dicen "edad".
Luego él ofrece:
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
Aquí hay varias sugerencias que implican comparar el mes y el día (¡y algunos lo malinterpretan, al no permitir el OR
como aquí correctamente!). Pero nadie ofreció dayofyear
, que parece tan simple y mucho más corto. Yo ofrezco:
DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
[Nota: ¡En ninguna parte de SQL BOL / MSDN está realmente documentado DATEPART(dayofyear, ...)
! Entiendo que es un número en el rango 1-366; lo más importante, no cambia según la configuración regional según DATEPART(weekday, ...)
& SET DATEFIRST
.]
EDITAR: Por qué el día de dayofyear
falla : como el usuario @AeroX comentó, si la fecha de nacimiento / inicio es posterior a febrero en un año no bisiesto, la edad se incrementa un día antes cuando la fecha actual / final es un año bisiesto, por ej. ''2015-05-26''
, ''2016-05-25''
da una edad de 1 cuando aún debería ser 0. Comparar el dayofyear
en años diferentes es claramente peligroso. Entonces, usar MONTH()
y DAY()
es necesario después de todo.
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
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
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
)
fuente: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/
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
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
SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int)
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
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
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