SQL问题:获取组中每条记录的Datediff(以天数为单位)

SQL问题:获取组中每条记录的Datediff(以天数为单位),sql,tsql,sql-server-2000,datediff,Sql,Tsql,Sql Server 2000,Datediff,鉴于此表: 如何获取每组ID号的每个状态日期之间的日期差(以天为单位)?换言之,我需要找到ID_编号给定的每个状态的已用天数 要知道的一些事情: 所有ID_号码都有一个接收日期,该日期应该是每个ID_号码的最早日期,但应用程序不强制执行 对于每个ID_编号,都会有一个具有相应状态日期的状态,该状态日期是ID_编号被赋予该特定状态的日期。 每次应用程序不执行时,“状态”列不一定总是按相同的顺序排列 所有ID号码都将有一个截止日期,该日期应为最新日期,但应用程序不强制执行 样本输出: 因此,对于ID

鉴于此表:

如何获取每组ID号的每个状态日期之间的日期差(以天为单位)?换言之,我需要找到ID_编号给定的每个状态的已用天数

要知道的一些事情:

所有ID_号码都有一个接收日期,该日期应该是每个ID_号码的最早日期,但应用程序不强制执行 对于每个ID_编号,都会有一个具有相应状态日期的状态,该状态日期是ID_编号被赋予该特定状态的日期。 每次应用程序不执行时,“状态”列不一定总是按相同的顺序排列 所有ID号码都将有一个截止日期,该日期应为最新日期,但应用程序不强制执行 样本输出: 因此,对于ID_编号2001,收到的第一个日期是2009-05-02,您遇到的下一个日期的状态为“打开”,是2009-05-02,因此经过的天数为0。转到下一个日期是2009-05-10,状态为“投资”,从上一个日期算起,已用天数为8天。遇到的下一个日期是2009-07-11,从上一个日期算起,经过的天数为62天

编辑以添加:

是否可以将已用天数作为此表/视图上的一列结束?
我还忘了加上这是SQL Server 2000。

一些示例输出确实会有帮助,但假设您需要每个ID\u编号/状态组合的信息,这只是猜测您的意思:

select ID_Number, Status, EndDate - StartDate as DaysElapsed
from (
    select ID_Number, Status, min(coalesce(received_date, status_date)) as StartDate, max(coalesce(closed_date, status_date)) as EndDate
    from Table1
    group by ID_Number, Status
) a

我的理解是,您需要相同id的第一个状态日期和下一个状态日期之间的差异,等等,直到结束日期

这只适用于SQL 2005及更高版本

;with test as (
    select 
        key,
        id_number,
        status,
        received_date,
        status_date,
        closed_date,
        row_number() over (partition by id order by status_date, key ) as rownum
    from @test
    )
select 
    t1.key,
    t1.id_number,
    t1.status,
    t1.status_date,
    t1.received_date,
    t1.closed_date,
    datediff(d, case when t1.rownum = 1 
                then t1.received_date
                else    
                    case when t2.status_date is null 
                        then t1.closed_date 
                        else t2.status_date 
                    end
            end,
            t1.status_date
         ) as days
from test t1
left outer join test t2
on t1.id = t2.id
    and t2.rownum = t1.rownum - 1
此解决方案将与SQL 2000配合使用,但我不确定其性能如何:

select *,
    datediff(d,
        case when prev_date is null
            then closed_date
            else prev_date
        end,
        status_date )
from ( 
    select *,
        isnull( ( select top 1 t2.status_date 
          from @test t2
          where t1.id_number = t2.id_number
            and t2.status_date < t1.status_date
          order by t2.status_date desc
          ),received_date) as prev_date 
    from @test t1
) a
order by id_number, status_date

注意:用表名替换@Test table。

棘手的一点是确定以前的状态,并将其与当前状态放在同一行上。如果键和StatusDate之间存在相关性,即Keyx>Keyy始终意味着StatusDatex>=StatusDatey,则会稍微简化。不幸的是,情况似乎并非如此

PS:我假设Key是您表上的唯一标识符;你没有说任何别的意思

SELECT  Key,
        ID_Number, 
        (
        SELECT  TOP 1 Key
        FROM    StatusUpdates prev
        WHERE   (prev.ID_Number = cur.ID_Number)
            AND (   (prev.StatusDate < cur.StatusDate)
                OR  (   prev.StatusDate = cur.StatusDate
                    AND prev.Key < cur.Key
                    )
                )
        ORDER BY StatusDate, Key /*Consider index on (ID_Number, StatusDate, Key)*/
        ) PrevKey
FROM    StatusUpdates cur
一旦你有了这个基础,就可以很容易地从当前或以前的状态更新中推断出你需要的任何其他信息。例如

SELECT  c.*,
        p.Status AS PrevStatus,
        p.StatusDate AS PrevStatusDate,
        DATEDIFF(d, c.StatusDate, p.StatusDate) AS DaysElapsed
FROM    (
        SELECT  Key,
                ID_Number, 
                Status,
                SattusDate,
                (
                SELECT  TOP 1 Key
                FROM    StatusUpdates prev
                WHERE   (prev.ID_Number = cur.ID_Number)
                    AND (   (prev.StatusDate < cur.StatusDate)
                        OR  (   prev.StatusDate = cur.StatusDate
                            AND prev.Key < cur.Key
                            )
                        )
                ORDER BY StatusDate, Key
                ) PrevKey
        FROM    StatusUpdates cur
        ) c
        JOIN StatusUpdates p ON
            p.Key = c.PrevKey

我将所有列添加到我的答案中,以用一个新的天数列复制原始表。如果没有结束日期,则为空。我已根据您添加到问题中的示例输出修改了结果。呃。在sql2000中实现这一点看起来很难看,因为我忘了在我的原始帖子中添加这些信息。@GregD:对于每个ID\u编号,键列总是连续的吗?键列是一个标识列,并且是自动递增的。话虽如此,但不能保证标识栏始终与其他任何内容保持一致。在这个应用程序中,这些日期是事后才想到的,而且没有任何业务规则。@GregD:我添加了一个与SQL 2000兼容的查询,但我不确定它在处理大型表时的性能有多好。