T-SQL:计算年龄然后将字符添加到结果中

时间:2017-03-30 18:56:24

标签: sql sql-server tsql

现在已经坚持了一段时间了。假设我有一个像这里的Client表:

Name   BirthDayNum   BirthMonthNum   BirthYearNum
--------------------------------------------------
John       23             12             1965
Jane        4              9             1975
Joe         6              3             1953

目前我正在使用以下语法计算年龄:(对不起,如果难以阅读)

DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2)) 
+ '-' + CAST(client.BirthDayNum AS varchar(2)) 
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE()) 
- (CASE WHEN dateadd(YY, DATEDIFF(year, CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2)) 
+ '-' + CAST(client.BirthDayNum AS varchar(2)) 
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101), GETDATE()), 
CONVERT(datetime, CAST(client.BirthMonthNum AS varchar(2)) 
+ '-' + CAST(client.BirthDayNum AS varchar(2)) 
+ '-' + CAST(client.BirthYearNum AS varchar(4)), 101)) > getdate() THEN 1 ELSE 0 END) AS 'Client Age'

这将给我多年的年龄。当然,如果我想要几个月,我只需将DATEDIFF(year更改为month。那么,我现在要做的就是这个。

继续计算年龄,但我不想返回几年或几个月,而是希望以年和月为单位返回年龄,而且还要在值内连续“y”和“m”。防爆。 Jane上面41码11米。

所以基本上我试图弄清楚如何在返回值中添加一个字符,以及计算年度计算之外的剩余月数。

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:5)

厌倦了用日期计算将自己扭曲成结,我创建了一个表值函数来计算年,月,日,小时,分钟和秒的经过时间。

示例

Declare @YourTable table (Name varchar(50),BirthDayNum int, BirthMonthNum int, BirthYearNum int)
Insert Into @YourTable values
('John', 23, 12, 1965),
('Jane',  4, 9,  1975),
('Joe',   6, 3,  1953)

Select A.Name
      ,B.*
      ,Age =  concat(C.Years,'y ',C.Months,'m')
 From @YourTable A
 Cross Apply (Select DOB = DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum)) B
 Cross Apply [dbo].[udf-Date-Elapsed](B.DOB,GetDate()) C

<强>返回

Name    DOB         Age
John    1965-12-23  51y 3m
Jane    1975-09-04  41y 6m
Joe     1953-03-06  64y 0m

UDF - 可能看起来有点矫枉过正,但效果非常好

CREATE FUNCTION [dbo].[udf-Date-Elapsed] (@D1 DateTime,@D2 DateTime)
Returns Table
Return (
    with cteBN(N)   as (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
         cteRN(R)   as (Select Row_Number() Over (Order By (Select NULL))-1 From cteBN a,cteBN b,cteBN c),
         cteYY(N,D) as (Select Max(R),Max(DateAdd(YY,R,@D1))From cteRN R Where DateAdd(YY,R,@D1)<=@D2),
         cteMM(N,D) as (Select Max(R),Max(DateAdd(MM,R,D))  From (Select Top 12 R From cteRN Order By 1) R, cteYY P Where DateAdd(MM,R,D)<=@D2),
         cteDD(N,D) as (Select Max(R),Max(DateAdd(DD,R,D))  From (Select Top 31 R From cteRN Order By 1) R, cteMM P Where DateAdd(DD,R,D)<=@D2),
         cteHH(N,D) as (Select Max(R),Max(DateAdd(HH,R,D))  From (Select Top 24 R From cteRN Order By 1) R, cteDD P Where DateAdd(HH,R,D)<=@D2),
         cteMI(N,D) as (Select Max(R),Max(DateAdd(MI,R,D))  From (Select Top 60 R From cteRN Order By 1) R, cteHH P Where DateAdd(MI,R,D)<=@D2),
         cteSS(N,D) as (Select Max(R),Max(DateAdd(SS,R,D))  From (Select Top 60 R From cteRN Order By 1) R, cteMI P Where DateAdd(SS,R,D)<=@D2)

    Select [Years]   = cteYY.N
          ,[Months]  = cteMM.N
          ,[Days]    = cteDD.N
          ,[Hours]   = cteHH.N
          ,[Minutes] = cteMI.N
          ,[Seconds] = cteSS.N
     From  cteYY,cteMM,cteDD,cteHH,cteMI,cteSS
)
--Max 1000 years
--Select * from [dbo].[udf-Date-Elapsed] ('1991-09-12 21:00:00.000',GetDate())

只是为了说明

没有任何辅助字符串操作的TVF将返回

Select A.Name
      ,B.*
 From @YourTable A
 Cross Apply [dbo].[udf-Date-Elapsed](DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum),GetDate()) B

enter image description here

  

编辑 - 只读版本

Select A.Name
      ,B.*
      ,Age =  concat(DateDiff(MONTH,B.DOB,GetDate())/12,'y ',DateDiff(MONTH,B.DOB,GetDate()) % 12,'m')
 From @YourTable A
 Cross Apply (Select DOB = DateFromParts(A.BirthYearNum,A.BirthMonthNum,A.BirthDayNum)) B

答案 1 :(得分:0)

是的,它更容易保存为DOB ..但是一个简单的方法

select concat( floor(datediff(year, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate()))-1, 'y ', datediff(month, datefromparts(birthyearnum,birthmonthnum,birthdaynum), getdate())%12, 'm')
    from #yourDates

1965年的年龄是多少41岁?

输入表:

create table #yourdates(Name varchar(10), BirthdayNum int, BirthMonthNum int, BirthYearNum int)

insert into #yourdates
(Name, BirthdayNum, BirthMonthNum, BirthYearNum) values
 ('John',      23        ,     12     ,        1965  )
,('Jane',       4        ,      9     ,        1975  )
,('Joe ',       6        ,      3     ,        1953  )

答案 2 :(得分:0)

如果你是2008年或更小,并且不能使用datefromparts ......

declare @table table ([Name] varchar(4), BirthDayNum int, BirthMonthNum int, BirthYearNum int)
insert into @table
values
('John',23,12,1965),
('Jane',4,9,1975),
('Day',30,3,1990)

;with cte as(
    select
        [Name],
        cast(BirthYearNum as varchar(4)) + '/' + cast(BirthMonthNum as varchar(2)) + '/' + cast(BirthDayNum as varchar(2)) as DOB
    from 
        @table)

select 
     [Name]
     ,DOB
     ,datediff(year,DOB,GETDATE()) as Years
     ,datediff(month,DOB,GETDATE()) %12 as Months
     ,rtrim(cast(datediff(year,DOB,GETDATE()) as char(2))) + 'y ' + rtrim(cast(datediff(month,DOB,GETDATE()) %12 as char(2))) + 'm' as  Age 
from cte