Wie berechnet man das Alter (in Jahren) basierend auf dem Geburtsdatum und getDate ()


171

Ich habe eine Tabelle mit Personen zusammen mit ihrem Geburtsdatum (derzeit ein nvarchar (25))

Wie kann ich das in ein Datum umwandeln und dann ihr 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

16
Warum speichern Sie Datumswerte mit nvarchar (25) als Zeichenfolgen, anstatt das native Datum oder den Datums- / Uhrzeittyp der Datenbank zu verwenden?
Jesper

Die Frage ist mit 2005 und nicht mit 2008 gekennzeichnet, sodass der native Datumstyp nicht verfügbar ist, aber definitiv eine Datums- und Uhrzeitangabe. Dies könnte als SmallDateTime bezeichnet werden, da Sie die Genauigkeit nicht benötigen.
Andrew

Hallo, der Grund für das Beibehalten von Datumsangaben als varchar ist, dass ich dies aus einem Nicht-SQL-Serverschema importiere. Es gab einige Probleme beim Importieren von datetime (und den anderen Datumsformaten) und der Konvertierung von varchar in Ordnung
Jimmy

7
@ James.Elsey, Sie hatten also Probleme beim Importieren und sind daher alle Daten gültig? Ich kann nie sicher sein, ob Sie mit varchar eine datetime oder smalldatetime verwenden. Mit varchar können Sie Ihren Import zum Laufen bringen, haben aber später andere Probleme. Außerdem würde ich niemals das Alter speichern, es ändert sich jeden Tag, benutze ein View
KM.

@KM Ja, es gab ein Problem beim Importieren dieser Daten als Datum. Die einzige praktikable Lösung war zu diesem Zeitpunkt, sie als NVARARS zu importieren. Diese Auswahl wird Teil eines nächtlichen Jobs sein, daher sollte das Speichern des Alters kein Problem sein
Jimmy

Antworten:


256

Es gibt Probleme mit Schaltjahr / -tagen 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 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 die oben ändern 10000zu 10000.0und Dezimalzahlen bekommen, aber es wird nicht unter so genau wie die Methode.

BESTE METHODE FÜR JAHRE IM DEZIMAL

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

24
Dies ist auch keine exakte Lösung. Wenn ich mein eigenes @dob als '1986-07-05 00:00:00' nehme und dies GETDATE()am '2013-07-04 23:59:59' ausführen würde (anstelle von ' andere Variable verwenden '), heißt es, dass ich Ich bin 27, während ich in diesem Moment noch nicht bin. Beispielcode: declare @startDate nvarchar(100) = '1986-07-05 00:00:00' declare @endDate nvarchar(100) = '2013-07-04 23:59:59' SELECT DATEDIFF(hour,@startDate,@endDate)/8766.0 AS AgeYearsDecimal ,CONVERT(int,ROUND(DATEDIFF(hour,@startDate,@endDate)/8766.0,0)) AS AgeYearsIntRound ,DATEDIFF(hour,@startDate,@endDate)/8766 AS AgeYearsIntTrunc
Bartlaarhoven

20
Dies ist nicht korrekt, da 8766 Stunden pro Jahr angenommen werden, was 365,25 Tagen entspricht. Da es keine Jahre mit 365,25 Tagen gibt, ist dies in der Nähe des Geburtsdatums der Person häufiger falsch als richtig. Diese Methode wird noch genauer sein.
Bacon Bits

1
Zweiter @ Bacon Bits-Kommentar - Dies ist häufig falsch, wenn das aktuelle Datum in der Nähe des Geburtsdatums einer Person liegt.
Flash

2
Ich denke, der erste Textblock macht diese Antwort verwirrend. Wenn Ihre aktualisierte Methode das Problem mit Schaltjahren nicht hat, würde ich vorschlagen (wenn Sie es wirklich überhaupt behalten möchten), es am Ende Ihrer Antwort nach unten zu verschieben.
Ajbeaven

1
Wenn Sie eine GENAUE Berechnung wünschen, wird DATEDIFF dies nicht tun @ShailendraMishra, da es ungefähr Tage usw. Gibt beispielsweise select datediff(year, '2000-01-05', '2018-01-04')18 zurück, nicht 17, wie es sollte. Ich habe das obige Beispiel unter der Überschrift "BESTE METHODE FÜR JAHRE IN INT" verwendet und es funktioniert perfekt. Vielen Dank!
Openwonk

132

Ich muss diesen da rauswerfen. Wenn Sie konvertieren das Datum im Stil 112 (JJJJMMTT) in eine Zahl , können Sie eine Berechnung wie diese verwenden ...

(yyyyMMdd - yyyyMMdd) / 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

14
Dies ist fast magisch, wie es alle Schaltjahrprobleme löst. Es kann erwähnenswert sein, dass 112 eine spezielle Nummer für die CONVERT-Funktion ist, die das Datum als yyyymmdd formatiert. Es ist möglicherweise nicht für jeden offensichtlich, wenn man es betrachtet.
Derek Tomes

5
Du bist ein Genie!
Ercan

Mein Team hatte ein Problem, als das Datum, an dem wir das Alter ermittelt haben, der gleiche Tag war wie das Datum, mit dem wir es vergleichen. Wir bemerkten, dass wenn sie am selben Tag waren (und wenn das Alter ungerade sein würde), das Alter um eins abweichen würde. Das hat perfekt funktioniert!
Der Sheek Geek

1
Dies ist die richtige Antwort - bitte markieren Sie sie als solche.
Snympi

4
Der einfachste / kürzeste Code für genau dieselbe Berechnungsmethode in SQL Server 2012+ istcode: SELECT [Age] = (0+ FORMAT(@as_of,'yyyyMMdd') - FORMAT(@bday,'yyyyMMdd') ) /10000 --The 0+ part tells SQL to calc the char(8) as numbers
ukgav

44

Ich habe diese Abfrage fast 10 Jahre lang in unserem Produktionscode verwendet:

SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age

6
Es ist nicht schlecht, aber nicht 100%. Der 16.10.2007 wird am 15.10.2009 ein Alter von 2 Jahren melden
Andrew

4
Doh, wir vermissen das Offensichtliche, es ist nach Mittag, getdate gibt ein int zurück, also wird es natürlich aufgerundet. Ich habe Ihre Antwort kopiert und ausgeführt, also automatisch getdate verwendet, nicht das Literal.
Andrew

2
Elegant und einfach. Vielen Dank!
William MB

9
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 alles mit dem Kalender zu tun hat. Jedes Mal, wenn derselbe Monat und Tag wie das Geburtsdatum verstrichen ist, erhöhen Sie das Alter um 1. Dies bedeutet, dass Folgendes am genauesten ist, da es widerspiegelt, was Menschen meinen, wenn sie "Alter" sagen:DATEDIFF(yy, @BirthDate, GETDATE()) - CASE WHEN (MONTH(@BirthDate) >= MONTH(GETDATE())) AND DAY(@BirthDate) > DAY(GETDATE()) THEN 1 ELSE 0 END
Bacon Bits

5
Entschuldigung, diese Syntax ist falsch. CASE WHEN (MONTH(@date) > MONTH(GETDATE())) OR (MONTH(@date) = MONTH(GETDATE()) AND DAY(@date) > DAY(GETDATE())) THEN 1 ELSE 0 END
Bacon Bits

31

So viele der oben genannten Lösungen sind falsch. DateDiff (yy, @ Dob, @PassedDate) berücksichtigt nicht den Monat und den Tag beider Daten. Auch die Dartteile zu nehmen und zu vergleichen funktioniert nur, wenn sie richtig bestellt sind.

DER FOLGENDE CODE FUNKTIONIERT UND IST 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

Warum multiplizieren Sie mit 100? Dies funktioniert für mich, da ich versuche, in der Datenbank zu replizieren, was in unserer Codebibliothek vorhanden ist - aber ich konnte Ihre Funktion nicht erklären. Dies könnte eine dumme Frage sein :)
Jen

6
Vielen Dank! Genau der Code, den ich hier erwartet hatte. Dies ist der einzige genau korrekte Code in diesem Thread ohne (hässliche) String-Transformationen! @Jen Es dauert den Monat und den Tag des DoB (wie den 25. September) und wandelt es in einen ganzzahligen Wert 0925(oder 925) um. Das Gleiche gilt für das aktuelle Datum (wie es der 16. Dezember wird 1216) und prüft dann, ob der DoB-Integer-Wert bereits übergeben wurde. Um diese ganze Zahl zu erstellen, sollte der Monat mit 100 multipliziert werden.
Bartlaarhoven

Danke @bartlaarhoven :)
Jen

Ich möchte nur erwähnen, dass dies zwar String-Transformationen vermeidet, aber stattdessen viel Casting ausführt. Meine Tests haben gezeigt, dass es nicht wesentlich schneller ist als die Antwort von dotjoe , und der Code ist ausführlicher.
StriplingWarrior

Die akzeptierte Antwort hat eine viel einfachere INT-Antwort:(CONVERT(int,CONVERT(char(8),@Now,112))-CONVERT(char(8),@Dob,112))/10000
KM.

19

Sie müssen die Art und Weise berücksichtigen, in der der datierte Befehl rundet.

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 aus angepasst habe .

Beachten Sie, dass der 28. Februar als Geburtstag eines Sprunges für Nicht-Schaltjahre betrachtet wird, z. B. wird eine am 29. Februar 2020 geborene Person am 28. Februar 2021 anstelle des 01. März 2021 als 1 Jahr alt angesehen.


@ Andrew - Korrigiert - Ich habe eine der Auswechslungen verpasst
Ed Harper

1
Vereinfachte VersionSELECT DATEDIFF(year, DOB, getdate()) + CASE WHEN (DATEADD(year,DATEDIFF(year, DOB, getdate()) , DOB) > getdate()) THEN - 1 ELSE 0 END)
Peter

Dies ist der richtige Ansatz; Ich verstehe nicht, warum Hacks so sehr positiv bewertet werden.
Salman A

8

BEARBEITEN: DIESE ANTWORT IST FEHLERHAFT. Ich lasse es hier als Warnung für jeden, der versucht ist, es zu verwenden dayofyear, mit einer weiteren Bearbeitung am Ende.


Wenn Sie wie ich nicht durch Bruchteile dividieren möchten oder Rundungs- / Schaltjahrfehler riskieren möchten, begrüße ich den Kommentar von @Bacon Bits in einem Beitrag über https://stackoverflow.com/a/1572257/489865, in dem 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 alles mit dem Kalender zu tun hat. Jedes Mal, wenn derselbe Monat und Tag wie das Geburtsdatum verstrichen ist, erhöhen Sie das Alter um 1. Dies bedeutet, dass das Folgende am genauesten ist, da es widerspiegelt, was Menschen meinen, 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 es falsch, wenn sie das ORhier nicht richtig berücksichtigen!). Aber niemand hat angeboten dayofyear, 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

[Hinweis: Nirgendwo in SQL ist BOL / MSDN DATEPART(dayofyear, ...)tatsächlich dokumentiert! Ich verstehe es als eine Zahl im Bereich von 1 bis 366; am wichtigsten ist, dass es sich nicht nach Gebietsschema gemäß DATEPART(weekday, ...)& ändert SET DATEFIRST.]


EDIT: Warum dayofyeargeht schief : Als Benutzer @AeroX hat kommentiert, wenn die Geburt / Startdatum ist nach dem Februar in einem Schaltjahr nicht, das Alter erhöht wird einen Tag früher , wenn der Strom / -ende ein Schaltjahr ist, zum Beispiel '2015-05-26', '2016-05-25'gibt eine Alter von 1, wenn es noch 0 sein sollte. Der Vergleich dayofyearin verschiedenen Jahren ist eindeutig gefährlich. Also mit MONTH()und DAY()ist doch nötig.


Dies sollte abgestimmt oder sogar als Antwort markiert werden. Es ist kurz, elegant und logisch korrekt.
z00l

1
Für alle, die nach Februar geboren wurden, wird ihr Alter mit der DayOfYearMethode einen Tag früher in jedem Schaltjahr erhöht .
AeroX

4
@AeroX Vielen Dank, dass Sie diesen Fehler entdeckt haben. Ich habe mich entschlossen, meine Lösung als Warnung für jeden zu belassen, der sie möglicherweise verwendet hat dayofyear, aber klar bearbeitet, um zu zeigen, warum sie schief geht. Ich hoffe das ist passend.
JonBrave

5

Da es keine einfache Antwort gibt, die immer das richtige Alter angibt, habe ich mir Folgendes 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 

Dies ergibt die Jahresdifferenz zwischen dem Geburtsdatum und dem aktuellen Datum. Dann wird ein Jahr abgezogen, wenn das Geburtsdatum noch nicht verstrichen ist.

Immer genau - unabhängig von Schaltjahren oder der Nähe zum Geburtsdatum.

Das Beste von allem - keine Funktion.


3
SELECT ID,
Name,
DATEDIFF(yy,CONVERT(DATETIME, DOB),GETDATE()) AS AGE,
DOB
FROM MyTable

1
Sie möchten getdate als zweites Argument und nicht als erstes, andernfalls erhalten Sie negative Zahlenergebnisse und Datumsangabenrunden. Wenn Sie also datiert auswählen (yy, '20081231', getdate ()), wird ein Alter von 1 angegeben, das jedoch nur 10 Monate alt ist .
Andrew

1
Diese Berechnung liefert falsche Berechnungen für Personen, die dieses Jahr noch keinen Geburtstag hatten.

3

Wie wäre es mit:

DECLARE @DOB datetime
SET @DOB='19851125'   
SELECT Datepart(yy,convert(date,GETDATE())-@DOB)-1900

Würde das nicht all diese Probleme beim Runden, Abschneiden und Versetzen vermeiden?


Ihre Berechnung ist nicht genau. Zum Beispiel: Es schlägt fehl, wenn Sie '1986-07-05 00:00:00'für DOB und '2013-07-04 23:59:59'für die aktuelle Zeit nehmen.
Drinovc

@ub_coding Bieten Sie eine andere Frage an und beantworten Sie sie oder stellen Sie sie?
Aaron C

dies: DECLARE @DOB datetime SET @ DOB = '19760229' SELECT Datepart (yy, convert (datetime, '19770228') - @ DOB) -1900 = 1 Das Hauptproblem ist die Lücke von 29 für die meisten Lösungen, die das Abschneiden von Rundungen usw. erklärt .
Leonardo Marques de Souza

3

Ich glaube, das ist ähnlich wie bei anderen, die hier gepostet wurden ... aber diese Lösung funktionierte für die Schaltjahrbeispiele vom 29.02.1976 bis zum 01.03.2011 und auch für den Fall für das erste Jahr .. wie 07/04 / 2011 bis 07/03/2012, die zuletzt über die Schaltjahrlösung veröffentlicht wurden, funktionierte für diesen Anwendungsfall des ersten Jahres nicht.

SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)

Gefunden hier .


3

Überprüfen Sie einfach, ob die folgende 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        
 )

2
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
)

Quelle: http://beginsql.wordpress.com/2012/04/26/how-to-calculate-age-in-sql-server/


Ein kürzerer Weg, dies in SQL Server 2012+ zu tun, ist wie folgt und vermeidet die Konvertierung in 112 und Floor ist nicht erforderlich:code: SELECT [Age] = (0+ FORMAT(@ToDate,'yyyyMMdd') - FORMAT(@DOB,'yyyyMMdd') ) /10000
ukgav

2

Ich habe viel darüber nachgedacht und gesucht und ich habe 3 Lösungen, die

  • Alter richtig berechnen
  • sind kurz (meistens)
  • sind (meistens) sehr verständlich.

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. Wenn es größer als das aktuelle Datum ist, wird ein Jahr abgezogen. Einfach richtig? Das einzige ist, dass sich der Unterschied in den Jahren hier verdoppelt.

Wenn Sie es jedoch nicht inline verwenden müssen, können Sie es folgendermaßen 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 von @ bacon-bits kopiert. Es ist am einfachsten zu verstehen, aber ein bisschen 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 in Folgendes umgestaltet:

DATEDIFF(YY, @DOB, @NOW) - 
  CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))

Dieser ist der kürzeste, aber am schwierigsten zu verstehen. 50ist nur ein Gewicht, daher ist der Tagesunterschied nur wichtig, wenn die Monate gleich sind. SIGNDie Funktion dient zum Transformieren eines beliebigen Werts in -1, 0 oder 1. Sie CEILING(0.5 *ist dieselbe wie, Math.max(0, value)aber in SQL gibt es so etwas nicht.


1
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

1
select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age

Hier gibt es viele 365,25 Antworten. Denken Sie daran, wie Schaltjahre definiert sind:

  • Alle vier Jahre
    • außer alle 100 Jahre
      • außer alle 400 Jahre

Hervorragende Antwort. Für diejenigen, die neugierig sind, ist hier eine Erklärung, warum 365.2425 der richtige Wert ist: grc.nasa.gov/WWW/k-12/Numbers/Math/Mathematical_Thinking/…
vvvv4d

0

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

0

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'

0

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

0

Dadurch 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()-@dob)

2
Behandelt Schaltjahre nicht richtig SELECT DATEDIFF (YEAR, '0: 0', convert (datetime, '2014-02-28') -'2012-02-29 ') ergibt 2, sollte aber nur 1 sein
Peter Kerr

0

Ed Harpers Lösung ist die einfachste, die ich gefunden habe und die niemals die falsche Antwort zurückgibt, wenn der Monat und der Tag der beiden Daten 1 oder weniger Tage voneinander entfernt sind. Ich habe eine leichte Ä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

0

Die als richtig gekennzeichnete Antwort ist näher an der Genauigkeit, schlägt jedoch im folgenden Szenario fehl : Geburtsjahr ist Schaltjahr und Tag nach Februar

declare @ReportStartDate datetime = CONVERT(datetime, '1/1/2014'),
@DateofBirth datetime = CONVERT(datetime, '2/29/1948')

FLOOR(DATEDIFF(HOUR,@DateofBirth,@ReportStartDate )/8766)


ODER

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 funktionierte in fast allen Szenarien, unter Berücksichtigung des Schaltjahres, des Datums als 29. Februar usw.

Bitte korrigieren Sie mich, wenn diese Formel eine Lücke hat.


Die endgültige Formel ist fast genau wie in dieser Antwort stackoverflow.com/a/1572235/168747 . Aber der hier ist weniger lesbar und enthält unnötige floor.
Marek

0
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

0

Hier ist, wie ich das Alter anhand eines Geburtsdatums und eines aktuellen Datums berechne.

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

0
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

-1: Wird jederzeit falsch sein, month(compare) > month(dob)ABER day(compare) < day(dob)z select dbo.AgeAtDate('2000-01-14', '2016-02-12').
JonBrave

Sie haben Recht, danke für diesen Fall, haben Funktion aktualisiert
Vova

0
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

0

Was ist mit einer Lösung, die nur Datumsfunktionen enthält, keine Mathematik, keine Sorgen um das 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

0

Nach dem Ausprobieren vieler Methoden funktioniert dies 100% der Zeit mit der modernen MS SQL FORMAT-Funktion, anstatt in Stil 112 zu konvertieren. Beides würde funktionieren, aber dies ist der geringste Code.

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

-2

Wir haben so etwas wie hier benutzt, aber dann das Durchschnittsalter genommen:

ROUND(avg(CONVERT(int,DATEDIFF(hour,DOB,GETDATE())/8766.0)),0) AS AverageAge

Beachten Sie, dass die RUNDE eher außen als innen ist. Dadurch kann die AVG genauer sein und wir runden nur einmal. Schneller machen.


-2
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 

-2
SELECT CAST(DATEDIFF(dy, @DOB, GETDATE()+1)/365.25 AS int)

Ich sehe Abstimmungen, aber ich sehe keine Beispiele, die beweisen, dass dies kaputt ist.
Alex
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.