T-SQL: calculate age, then add character to result

Stuck on this for a while. Let's say I have a table Client

like here:

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

      

I am currently calculating age using this syntax: (sorry if it's hard to read)

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'

      

This will give me the age in years. Of course, if I need months, I just change DATEDIFF(year

to month

. So now I am trying to do this.

Keep calculating age, but instead of returning either years or months, I would like to return the age in years and months, but also the concat 'y' and 'm' within the value. Ex. 41st 11m for Jane above.

So, basically I'm trying to figure out how to add a char to the return value, and also calculate the remaining months after calculating the year.

Any help would be greatly appreciated!

+3


source to share


3 answers


Tired of twisting myself into knots with date calculations, I created a table-value-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

      

UDF - May sound like overkill, but very effective

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

      



For illustration purposes only

TVF without any secondary string manipulation will return

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

CHANGE 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

      

+5


source


Yes, it's 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 old is the 1965 age 41?



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


source


If you are on 2008 or less and cannot 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


source







All Articles