Jim*_*mmy 157 sql-server select sql-server-2005 date
我有一张桌子列出了人们的出生日期(目前是nvarchar(25))
如何将其转换为日期,然后计算年龄?
我的数据如下
ID Name DOB
1 John 1992-01-09 00:00:00
2 Sally 1959-05-20 00:00:00
Run Code Online (Sandbox Code Playgroud)
我想看看:
ID Name AGE DOB
1 John 17 1992-01-09 00:00:00
2 Sally 50 1959-05-20 00:00:00
Run Code Online (Sandbox Code Playgroud)
KM.*_*KM. 238
闰年/日期存在问题以及以下方法,请参阅以下更新:
试试这个:
Run Code Online (Sandbox Code Playgroud)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 AgeYearsIntTruncOUTPUT:
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
你可以改变上面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
Run Code Online (Sandbox Code Playgroud)
dot*_*joe 116
得扔掉这个.如果您使用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
Run Code Online (Sandbox Code Playgroud)
产量
20091015 19800420 290595 29
Run Code Online (Sandbox Code Playgroud)
J__*_*J__ 40
我在生产代码中使用了这个查询近10年:
SELECT FLOOR((CAST (GetDate() AS INTEGER) - CAST(Date_of_birth AS INTEGER)) / 365.25) AS Age
Run Code Online (Sandbox Code Playgroud)
小智 30
上面的许多解决方案都是错误的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
Run Code Online (Sandbox Code Playgroud)
Ed *_*per 15
您需要考虑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>
Run Code Online (Sandbox Code Playgroud)
我从这里改编
编辑:这个答案是不正确的. 我把它留在这里作为对任何想要使用的人的警告dayofyear,最后进行进一步的编辑.
如果像我一样,你不想除以小数天或冒险四舍五入/闰年错误,我赞成@Bacon Bits在/sf/answers/110058021/上的帖子中发表评论,他说:
如果我们谈论人类年龄,你应该按照人类计算年龄的方式来计算它.它与地球的移动速度和与日历有关的一切都没有任何关系.每当同一个月和一天都作为出生日期过去时,你将年龄增加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
Run Code Online (Sandbox Code Playgroud)
这里有几个建议涉及比较月份和日期(有些错误,未能在OR这里正确地允许!).但没有人提供dayofyear,这似乎是如此简单和短得多.我提供:
DATEDIFF(year, @date, GETDATE()) -
CASE WHEN DATEPART(dayofyear, @date) > DATEPART(dayofyear, GETDATE()) THEN 1 ELSE 0 END
Run Code Online (Sandbox Code Playgroud)
[注意:SQL BOL/MSDN中没有任何内容可以DATEPART(dayofyear, ...)返回实际记录的内容!我理解它是1--366范围内的数字; 最重要的是,它并没有按区域按更改DATEPART(weekday, ...)&SET DATEFIRST]
编辑: 为什么dayofyear出错:正如用户@AeroX评论的那样,如果出生/开始日期是非闰年的2月之后,当前/结束日期是闰年时,年龄会提前一天递增,例如'2015-05-26','2016-05-25'给出当它应该仍为0时,年龄为1岁.比较dayofyear不同年份显然是危险的.所以使用MONTH()并且DAY()毕竟是必要的.
我相信这与此处发布的其他解决方案类似......但该解决方案适用于 02/29/1976 至 03/01/2011 的闰年示例,并且也适用于第一年的案例......如 07/04 /2011 到 07/03/2012,最后一个发布的关于闰年的解决方案不适用于第一年的用例。
SELECT FLOOR(DATEDIFF(DAY, @date1 , @date2) / 365.25)
Run Code Online (Sandbox Code Playgroud)
在这里找到。
由于没有一个简单的答案总是给出正确的年龄,这就是我想出的.
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
Run Code Online (Sandbox Code Playgroud)
这将获得出生日期和当前日期之间的年份差异.如果生日还没有过去,那么它会减去一年.
始终准确 - 无论闰年或接近生日.
最重要的是 - 没有功能.
我对此做了很多思考和搜索,我有 3 个解决方案
以下是测试值:
DECLARE @NOW DATETIME = '2013-07-04 23:59:59'
DECLARE @DOB DATETIME = '1986-07-05'
Run Code Online (Sandbox Code Playgroud)
解决方案1:我在一个js库中找到了这种方法。这是我最喜欢的。
DATEDIFF(YY, @DOB, @NOW) -
CASE WHEN DATEADD(YY, DATEDIFF(YY, @DOB, @NOW), @DOB) > @NOW THEN 1 ELSE 0 END
Run Code Online (Sandbox Code Playgroud)
它实际上是在 DOB 上加上年份差异,如果它大于当前日期,则减去一年。简单吧?唯一的问题是这里重复了年份的差异。
但如果你不需要内联使用它,你可以这样写:
DECLARE @AGE INT = DATEDIFF(YY, @DOB, @NOW)
IF DATEADD(YY, @AGE, @DOB) > @NOW
SET @AGE = @AGE - 1
Run Code Online (Sandbox Code Playgroud)
解决方案 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
Run Code Online (Sandbox Code Playgroud)
它基本上是像我们人类一样计算年龄。
解决方案3:我的朋友将其重构为:
DATEDIFF(YY, @DOB, @NOW) -
CEILING(0.5 * SIGN((MONTH(@DOB) - MONTH(@NOW)) * 50 + DAY(@DOB) - DAY(@NOW)))
Run Code Online (Sandbox Code Playgroud)
这是最短但最难理解的。50只是一个重量,因此只有当月份相同时,日差才重要。SIGN函数用于将它得到的任何值转换为 -1、0 或 1。CEILING(0.5 *与 相同Math.max(0, value),但 SQL 中没有这样的东西。
select floor((datediff(day,0,@today) - datediff(day,0,@birthdate)) / 365.2425) as age
Run Code Online (Sandbox Code Playgroud)
这里有很多365.25的答案。记住闰年是如何定义的:
| 归档时间: |
|
| 查看次数: |
559205 次 |
| 最近记录: |