Ich habe eine Tabelle mit Personen und ihrem Geburtsdatum (derzeit nvarchar (25)).
Wie kann ich das in ein Datum umwandeln und dann das Alter in Jahren berechnen?
Meine Daten sehen wie folgt aus
ID Name DOB
1 John 1992-01-09 00:00:00
2 Sally 1959-05-20 00:00:00
Ich würde gerne ... sehen:
ID Name AGE DOB
1 John 17 1992-01-09 00:00:00
2 Sally 50 1959-05-20 00:00:00
Es gibt Probleme mit Schaltjahrtagen und der folgenden Methode, siehe Update unten:
versuche dies:
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
AUSGABE:
AgeYearsDecimal AgeYearsIntRound AgeYearsIntTrunc --------------------------------------- ---------------- ---------------- 17.767054 18 17 (1 row(s) affected)
/ - _ update _ Hier sind einige genauere Methoden:
BESTE METHODE FÜR JAHRE IN 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
sie können den obigen 10000
in 10000.0
ändern und Dezimalzahlen erhalten, dies ist jedoch nicht so genau wie die unten beschriebene Methode.
BESTE METHODE FÜR JAHRE IN DEKIMAL
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
Muss ich da rausschmeißen. Wenn Sie konvertieren das Datum unter Verwendung des 112-Stils (JJJJMMTT) in eine Zahl umwandeln, können Sie eine Berechnung wie diese verwenden ...
(JJJJMMTT - JJJJMMTT)/10000 = Differenz in vollen Jahren
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
ausgabe
20091015 19800420 290595 29
Ich habe diese Abfrage seit fast 10 Jahren in unserem Produktionscode verwendet:
SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
Viele der oben genannten Lösungen sind falsch. DateDiff (yy, @ Dob, @PassedDate) berücksichtigt nicht den Monat und den Tag beider Datumsangaben. Auch das Nehmen der Dartteile und das Vergleichen funktionieren nur, wenn sie ordnungsgemäß bestellt wurden.
DER FOLGENDE CODE FUNKTIONIERT UND IS] SEHR EINFACH:
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
Sie müssen die Art und Weise bedenken, wie der Befehl von Datediff abgerundet wird.
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>
Was ich von hier angepasst habe
BEARBEITEN: DIESE ANTWORT IS INCORRECT. Ich lasse es hier als Warnung für alle, die in Versuchung sind benutze dayofyear
, mit einem weiteren Edit am Ende.
Wenn Sie, wie ich, nicht durch gebrochene Tage oder Fehler bei der Rundung des Risikos/Schaltjahres dividieren möchten, begrüße ich @Bacon Bits Kommentar in einem Beitrag oben https://stackoverflow.com/a/1572257/489865 wo er sagt:
Wenn wir über das menschliche Alter sprechen, sollten Sie es so berechnen, wie Menschen das Alter berechnen. Es hat nichts damit zu tun, wie schnell sich die Erde bewegt und was mit dem Kalender zu tun hat. Jedes Mal, wenn derselbe Monat und Tag wie das Geburtsdatum vergeht, erhöhen Sie das Alter um 1. Dies bedeutet, dass das Folgende am genauesten ist, da es die Bedeutung von Menschen widerspiegelt, wenn sie "Alter" sagen.
Er bietet dann an:
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
Es gibt hier einige Vorschläge zum Vergleichen von Monat und Tag (und einige verstehen das falsch, da OR
hier nicht korrekt angegeben wurde!). Aber niemand hat dayofyear
angeboten, was so einfach und viel kürzer erscheint. Ich biete:
DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
[Anmerkung: Nirgendwo in SQL BOL/MSDN ist das, was DATEPART(dayofyear, ...)
zurückgibt, tatsächlich dokumentiert! Ich verstehe es als eine Zahl im Bereich von 1-366; Am wichtigsten ist jedoch, dass nicht nach Gebietsschema gemäß DATEPART(weekday, ...)
& SET DATEFIRST
geändert wird.
EDIT: Warum dayofyear
schief geht: Als Benutzer hat @AeroX kommentiert, ob die Geburt/Das Startdatum liegt nach Februar in einem Nicht-Schaltjahr. Das Alter wird einen Tag früher erhöht, wenn das aktuelle/Enddatum ein Schaltjahr ist, z '2015-05-26'
, '2016-05-25'
Gibt ein Alter von 1 an, wenn es noch 0 sein sollte. Der Vergleich von dayofyear
in verschiedenen Jahren ist eindeutig gefährlich. Es ist also immerhin notwendig, MONTH()
und DAY()
zu verwenden.
Da es keine einfache Antwort gibt, die immer das richtige Alter angibt, habe ich mir das hier ausgedacht.
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
Dadurch wird die Jahresdifferenz zwischen dem Geburtsdatum und dem aktuellen Datum ermittelt. Dann wird ein Jahr abgezogen, wenn das Geburtsdatum noch nicht vergangen ist.
Immer genau - unabhängig von Schaltjahren oder wie nah am Geburtsdatum.
Das Beste von allem - keine Funktion.
Ich glaube, das ist ähnlich wie bei anderen, die hier veröffentlicht wurden. Diese Lösung funktionierte jedoch für die Schaltjahr-Beispiele 29.02.1976 bis 01.03.2011 und auch für das erste Jahr/2011 bis 07/03/2012, die der letzte über die Lösung des Schaltjahrs veröffentlichte, funktionierte für diesen ersten Anwendungsfall nicht.
SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)
Gefunden hier .
Wie wäre es mit:
DECLARE @DOB datetime
SET @DOB='19851125'
SELECT Datepart(yy,convert(date,GETDATE())[email protected])-1900
Würde das nicht all diese Rundungen, Verkürzungen und Aufhebungsprobleme vermeiden?
Prüfen Sie einfach, ob die unten stehende Antwort möglich ist.
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
)
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable
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
)
source: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/
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
Ich habe viel darüber nachgedacht und gesucht, und ich habe 3 Lösungen dafür
Hier sind Testwerte:
DECLARE @NOW DATETIME = '2013-07-04 23:59:59'
DECLARE @DOB DATETIME = '1986-07-05'
Lösung 1: Ich habe diesen Ansatz in einer js-Bibliothek gefunden. Es ist mein Favorit.
DATEDIFF(YY, @DOB, @NOW) -
CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END
Es fügt dem DOB tatsächlich einen Unterschied in Jahren hinzu, und wenn es größer als das aktuelle Datum ist, wird ein Jahr abgezogen. Einfach richtig? Das einzige ist, dass der Unterschied in Jahren hier doppelt vorhanden ist.
Wenn Sie es jedoch nicht inline verwenden müssen, können Sie es so schreiben:
DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW)
IF DATEADD(YY, @AGE, @DOB) > @NOW
SET @AGE = @AGE - 1
Lösung 2: Diese habe ich ursprünglich aus @ Speck-Bits kopiert. Es ist am einfachsten zu verstehen, aber etwas lang.
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
Es berechnet im Grunde das Alter wie wir Menschen.
Lösung 3: Mein Freund hat es folgendermaßen geändert:
DATEDIFF(YY, @DOB, @NOW) -
CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))
Dieses ist das kürzeste, aber es ist am schwersten zu verstehen. 50
ist nur ein Gewicht, daher ist der Tagesunterschied nur wichtig, wenn die Monate gleich sind. Die Funktion SIGN
dient zum Umwandeln des Werts in -1, 0 oder 1. CEILING(0.5 *
ist das gleiche wie Math.max(0, value)
, in SQL gibt es jedoch keine solche Funktion.
Die Lösung von Ed Harper ist die einfachste, die ich gefunden habe. Sie gibt niemals die falsche Antwort zurück, wenn der Monat und der Tag der beiden Daten 1 oder weniger Tage auseinander liegen. Ich habe eine kleine Änderung vorgenommen, um mit dem negativen Alter umzugehen.
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
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
Versuche dies
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'
Nachdem Sie die MANY-Methoden ausprobiert haben, funktioniert dies zu 100% mit der modernen MS SQL-Funktion FORMAT, anstatt in den Stil 112 zu konvertieren.
Kann jemand eine Datumskombination finden, die nicht funktioniert? Ich glaube nicht, dass es einen gibt :)
--Set parameters, or choose from table.column instead:
DECLARE @DOB DATE = '2000/02/29' -- If @DOB is a leap day...
,@ToDate DATE = '2018/03/01' --...there birthday in this calculation will be
--0+ part tells SQL to calc the char(8) as numbers:
SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
Damit werden die Probleme mit dem Geburtstag und der Rundung korrekt behandelt:
DECLARE @dob datetime
SET @dob='1992-01-09 00:00:00'
SELECT DATEDIFF(YEAR, '0:0', getdate()[email protected])
select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age
Es gibt hier eine Menge von 365,25 Antworten. Denken Sie daran, wie Schaltjahre definiert sind:
Wie wäre es mit einer Lösung mit nur Datumsfunktionen, nicht mit Mathematik, nicht mit dem Schaltjahr
CREATE FUNCTION dbo.getAge(@dt datetime)
RETURNS int
AS
BEGIN
RETURN
DATEDIFF(yy, @dt, getdate())
- CASE
WHEN
MONTH(@dt) > MONTH(GETDATE()) OR
(MONTH(@dt) = MONTH(GETDATE()) AND DAY(@dt) > DAY(GETDATE()))
THEN 1
ELSE 0
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
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
So berechne ich das Alter unter Berücksichtigung des Geburtsdatums und des aktuellen Datums.
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
Die als richtig markierte Antwort ist näher an der Genauigkeit, schlägt jedoch im folgenden Szenario fehl - wo Geburtsjahr ist Sprungjahr und -tag sind nach dem Februar-Monat
declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
@DateofBirth datetime = CONVERT(datetime, '2/29/1948')
FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766)
OR
FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8765.82) -- Divisor is more accurate than 8766
- Die folgende Lösung liefert genauere Ergebnisse.
FLOOR(DATEDIFF(YEAR,@DateofBirth,@ReportStartDate) - (CASE WHEN DATEADD(YY,DATEDIFF(YEAR,@DateofBirth,@ReportStartDate),@DateofBirth) > @ReportStartDate THEN 1 ELSE 0 END ))
Es hat in fast allen Szenarien funktioniert, unter Berücksichtigung des Schaltjahres, des Datums als 29. Februar usw.
Bitte korrigieren Sie mich, wenn diese Formel eine Lücke aufweist.
Wie wäre es damit:
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
Versuchen Sie diese Lösung:
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