T-SQL: calculate age then add character to result

前端 未结 3 1539
轮回少年
轮回少年 2021-01-14 04:47

Been stuck on this one for a while now. Let\'s say I have a Client table like the one here:

Name   BirthDayNum   BirthMonthNum   BirthYearNum
--         


        
相关标签:
3条回答
  • 2021-01-14 05:18

    Tired of twisting myself into knots with date calculations, I created a Table-Valued-Function to calculate elapsed time in Years, Months, Days, Hours, Minutes, and Seconds.

    Example

    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
    

    Returns

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

    The UDF - May look like overkill, but it is very performant

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

    Just to Illustrate

    The TVF without any secondary string manipulation would return

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

    EDIT - READ ONLY VERSION

    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
    
    0 讨论(0)
  • 2021-01-14 05:22

    Yes it is easier to save as DOB.. But one simple method

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

    How age for 1965 is 41y?

    Input table:

    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  )
    
    0 讨论(0)
  • 2021-01-14 05:39

    If you are on 2008 or lesser and can't use 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
    
    0 讨论(0)
提交回复
热议问题