SQL问题:在组中的每条记录的过去几天内获取Datediff

时间:2010-01-29 23:41:44

标签: sql tsql sql-server-2000 datediff

鉴于此表:

alt text

如何在每个ID_Number组的每个status_date之间获取日期?换句话说,我需要找到已给出ID_Number的每个状态的已用天数。

有些事要知道:

  • 所有ID_Number都有一个received_date,它应该是每个ID_Number的最早日期(但app不强制执行)
  • 对于每个ID_Number,将有一个状态,其中包含相应的status_date,即ID_Number被赋予该特定状态的日期。
  • 状态列并不总是每次都以相同的顺序(应用程序不强制执行)
  • 所有ID_Number都有一个closed_date,应该是最新日期(但app不会强制执行)

示例输出: 因此对于ID_Number 2001,第一个日期(received_date)是2009-05-02,并且您遇到的下一个日期的状态为“打开”并且是2009-05-02所以过去的天数是0.继续到下一个遇到的日期是2009-05-10,状态为“投资”,经过的天数是从前一天算起的8天。遇到的下一个日期是2009-07-11,经过的天数是从上一个日期算起的62天。

已编辑添加:

是否可以将经过的天数作为此表/视图中的列结束? 我也忘了添加这是SQL Server 2000。

3 个答案:

答案 0 :(得分:1)

我的理解是,您需要第一个status_date和下一个status_date之间的区别为同一个ID,依此类推,直至closed_date。

这只适用于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表替换为您的表名。

答案 1 :(得分:0)

一些示例输出确实会有所帮助,但这是猜测你的意思,假设你想要每个ID_Number / Status组合的信息:

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

答案 2 :(得分:0)

棘手的一点是确定先前的状态并将其与当前状态放在同一行。如果KeyStatusDate之间存在相关性(即Key(x) > Key(y)始终隐含StatusDate(x) >= StatusDate(y)),则会略微简化。不幸的是,情况似乎并非如此。

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

一旦将此作为基础,就可以轻松地从当前或以前的StatusUpdate推断出您需要的任何其他信息。 E.g。

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