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

时间:2022-08-16 01:27:56

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
--------------------------------------------------
John       23             12             1965
Jane        4              9             1975
Joe         6              3             1953

Currently I am calculating the age using this syntax: (sorry if it is 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 want months, I just change the DATEDIFF(year to month. So, what I am trying to do now is this.

这将使我的年龄以年为单位。当然,如果我想要几个月,我只需要将DATEDIFF(年到月)进行更改。我现在要做的是。

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

继续计算年龄,但不返回年份或月份,我希望返回年份和月份,但同时,也要返回值内的“y”和“m”。对Jane来说,上面是41y 11m。

So basically I am trying to figure out how to add a char to the return value, as well as calculate the remaining months beyond the year calculation.

所以基本上,我想弄清楚如何在返回值中添加一个char,同时计算出年度计算之后的剩余月份。

Any help would be greatly appreciated!

如有任何帮助,我们将不胜感激!

3 个解决方案

#1


5  

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

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

Just to Illustrate

只是为了说明

The TVF without any secondary string manipulation would return

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

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

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

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

#2


0  

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

是的,像DOB一样存钱更容易。但一个简单的方法

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?

1965年的年龄是多少?

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  )

#3


0  

If you are on 2008 or lesser and can't use datefromparts...

如果你在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

#1


5  

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

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

Just to Illustrate

只是为了说明

The TVF without any secondary string manipulation would return

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

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

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

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

#2


0  

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

是的,像DOB一样存钱更容易。但一个简单的方法

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?

1965年的年龄是多少?

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  )

#3


0  

If you are on 2008 or lesser and can't use datefromparts...

如果你在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