在SQL

时间:2017-01-11 18:07:23

标签: sql sql-server-2012 case datediff getdate

我需要一些帮助SQL Server 2012尝试计算报告的老化年份字段。

基本上,我有两个字段StartDateTime和EndDateTime,下面是一些示例数据:

StartDateTime                 EndDateTime

 2006-10-10 16:08:13.523      2008-04-11 00:00:00.000
 2016-05-11 13:03:48.093      2016-06-16 00:00:00.000
 2016-08-01 12:44:42.990      2016-08-01 00:00:00.000
 2016-05-20 17:33:27.957      2016-05-25 00:00:00.000
 2006-10-19 21:41:41.350      NULL

我目前正在尝试创建一个AgingYears字段来计算两个字段之间的年龄(尽可能精确)。当EndDateTime为NULL时,它应该计算GETDATE()和StartDateTime之间的差异。当StartDateTime大于EndDateTime时(我不知道为什么我有这样的数据,但我知道),那么它应该返回0。

我尝试根据我发现相关的网站做一些代码,但它对我帮助不大,这就是我所困扰的地方:

DATEDIFF(YY, StartDateTime, EndDateTime) - 
    CASE
        WHEN DATEADD(YY,DATEDIFF(YY,StartDateTime, EndDateTime),StartDateTime)
            > A.[END_DTTM] 
        THEN DATEDIFF(YY, StartDateTime, EndDateTime)- 1
        ELSE DATEDIFF(YY, StartDateTime, EndDateTime)
    END AS AgeInYears,

我非常感谢您对我的代码的任何帮助。

2 个答案:

答案 0 :(得分:2)

小心闰年。你想如何对待2月29日到2月28日?

case
    when year(coalesce(EndDateTime, getdate()) > year(StartDateTime)
    then
        datediff(year, StartDateTime, coalesce(EndDateTime, getdate())) -
        case
            when
                EndDateTime is not null and 
                    datepart(month, EndDateTime) < datepart(month, StartDateTime)
                or  datepart(month, EndDateTime) = datepart(month, StartDateTime)
                and datepart(day,   EndDateTime) < datepart(day,   StartDateTime)
            then 1
            when
                EndDateTime is null and
                    datepart(month, getdate())   < datepart(month, StartDateTime)
                or  datepart(month, getdate())   = datepart(month, StartDateTime)
                and datepart(day,   getdate())   < datepart(day,   StartDateTime)
            then 1
            else 0
        end
    else 0
end

我将EndDateTimegetdate()个案分开,主要是因为如果没有长线上的滚动条,它看起来会更好。

这是调整逻辑并捕捉闰日条件的一种方法,即使日期并不严格重合,也将其视为一整年。如果你按照我上面的方式保留“拆分”逻辑,你需要在两个分支中复制这个表达式(替换getdate() for EndDateTime everywhere except the为null`test)。

            when
                EndDateTime is not null and
                    datepart(month, EndDateTime)     < datepart(month, StartDateTime)
                 or datepart(month, EndDateTime)     = datepart(month, StartDateTime)
                and datepart(day,   EndDateTime)     < datepart(day,   StartDateTime)
                and not -- here's one way to catch the leap day condition
                (
                    -- adding one day this way is deprecated and only works with datetime
                    and datepart(month, StartDateTime + 1) > datepart(month, StartDateTime)
                    and datepart(month, EndDateTime + 1)   > datepart(month, EndDateTime)
                )

http://rextester.com/SBH69843

顺便说一下,一旦你理解了这种方法,就可以用yyyymmdd格式的数字算术来压缩相同的逻辑。

(
cast(convert(varchar(8), @EndDateTime, 120) as int) -
cast(convert(varchar(8), @StartDateTime, 120) as int)
) / 10000

上面所有复杂的逻辑只是借用减法中的年份。这几乎是一回事。

答案 1 :(得分:1)

我认为应该是这样的:

SELECT StartDate
    , EndDate
    , CASE 
        WHEN DATEDIFF(YY, StartDate, ISNULL(EndDate, GETDATE())) < 0
            THEN 0
        ELSE DATEDIFF(YY, StartDate, ISNULL(EndDate, GETDATE()))
        END AS AgingYears
FROM YourTableName