Il y a des problèmes avec les années/jours bissextiles et la méthode suivante, voir la mise à jour ci-dessous :
Essayez ceci :
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
SORTIE :
AgeYearsDecimal AgeYearsIntRound AgeYearsIntTrunc
--------------------------------------- ---------------- ----------------
17.767054 18 17
(1 row(s) affected)
UPDATE voici des méthodes plus précises :
MEILLEURE MÉTHODE POUR LES ANNÉES 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
vous pouvez modifier ce qui précède 10000
à 10000.0
et obtenir des décimales, mais elle ne sera pas aussi précise que la méthode ci-dessous.
MEILLEURE MÉTHODE POUR LES ANNÉES EN DÉCIMAL
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
16 votes
Pourquoi stockez-vous les valeurs de date sous forme de chaînes en utilisant nvarchar(25) au lieu d'utiliser le type natif de date ou datetime de la base de données ?
0 votes
La question étant étiquetée 2005 et non 2008, le type natif 'Date' n'est pas disponible, mais il s'agit bien d'une date, et l'on pourrait dire SmallDateTime puisque vous n'avez pas besoin de précision.
0 votes
Bonjour, la raison pour laquelle j'ai gardé les dates en tant que varchar est que j'importe ceci à partir d'un schéma non-SQL Server, il y a eu quelques problèmes en les important en tant que datetime (et les autres formats de date) et varchar a été converti sans problème.
7 votes
@James.Elsey, vous avez donc eu des problèmes d'importation et par conséquent toutes les dates sont-elles valides ? On ne peut jamais être sûr à moins d'utiliser un datetime ou smalldatetime, avec varchar, vous pouvez faire fonctionner votre importation, mais avoir d'autres problèmes en cours de route. De plus, je ne stockerai jamais l'âge, il change chaque jour, utilisez une vue.
0 votes
@KM Oui, il y avait un problème pour importer ces données sous forme de date, la seule solution viable à l'époque était de les importer sous forme de nvarchars. Cette sélection va faire partie d'un travail de nuit, donc le stockage de l'âge ne devrait pas être un problème.