SQL Server查找不同行之间的datediff并基于分组求和

SQL Server查找不同行之间的datediff并基于分组求和,sql,sql-server,Sql,Sql Server,我希望在此扩展公认的答案: 扩展数据集: ID | Time |OnOffSite| UserName | Reason ------------------------------------------------------ 123 | 2011-10-25 09:00:00.000 | on | Bloggs Joe | NULL 124 | 2011-10-25 12:00:00.000 | off | Bloggs Jo

我希望在此扩展公认的答案:

扩展数据集:

ID  | Time                    |OnOffSite| UserName   | Reason
------------------------------------------------------
123 | 2011-10-25 09:00:00.000 | on      | Bloggs Joe | NULL
124 | 2011-10-25 12:00:00.000 | off     | Bloggs Joe | Shift
125 | 2011-10-25 13:00:00.000 | on      | Bloggs Joe | NULL
126 | 2011-10-25 17:00:00.000 | off     | Bloggs Joe | Travel
127 | 2011-10-25 09:00:00.000 | on      | Jonesy Ian | NULL
128 | 2011-10-25 10:00:00.000 | on      | Jonesy Ian | NULL
129 | 2011-10-25 11:00:00.000 | off     | Jonesy Ian | End Shift
130 | 2011-10-25 12:00:00.000 | on      | Jonesy Ian | NULL
131 | 2011-10-25 15:00:00.000 | off     | Jonesy Ian | OverTime
我尝试通过新专栏扩展提供的答案分组,但没有成功:

-- =====================
-- sample data
-- =====================
declare @t table
(
    ID int,
    Time datetime,
    OnOffSite varchar(3),
    UserName varchar(50),
    Reason varchar(50)
)

insert into @t values(123, '2011-10-25 09:00:00.000', 'on', 'Bloggs Joe', 'NULL')
insert into @t values(124, '2011-10-25 12:00:00.000', 'off', 'Bloggs Joe', 'Shift')
insert into @t values(125, '2011-10-25 13:00:00.000', 'on', 'Bloggs Joe', 'NULL')
insert into @t values(126, '2011-10-25 17:00:00.000', 'off', 'Bloggs Joe', 'Travel')
insert into @t values(127, '2011-10-25 09:00:00.000', 'on', 'Jonesy Ian', 'NULL')
insert into @t values(128, '2011-10-25 10:00:00.000', 'on', 'Jonesy Ian', 'NULL')
insert into @t values(129, '2011-10-25 11:00:00.000', 'off', 'Jonesy Ian', 'Travel')
insert into @t values(130, '2011-10-25 12:00:00.000', 'on', 'Jonesy Ian', '')
insert into @t values(131, '2011-10-25 15:00:00.000', 'off', 'Jonesy Ian', 'Shift')

-- =====================
-- solution
-- =====================
select
    UserName, Reason,  diffinhours = DATEDIFF(hh, timeon, timeoff)
from
(
    select
        UserName,
        Reason, 
        timeon = max(case when k = 2 and OnOffSite = 'on' then Time end),
        timeoff = max(case when k = 1 and OnOffSite = 'off' then Time end)
    from
    (
        select
            ID,
            UserName,
            Reason, 
            OnOffSite,
            Time,
            rn = ROW_NUMBER() over(partition by username, Reason,  order by id)
        from
        (
            select
                ID,
                UserName,
                Reason, 
                OnOffSite,
                Time,
                rn2 = case OnOffSite 
                -- '(..order by id)' takes earliest 'on' in the sequence of 'on's
                -- to take the latest use '(...order by id desc)'
                when 'on' then 
                    ROW_NUMBER() over(partition by UserName, Reason,  OnOffSite, rn1 order by id)
                -- '(... order by id desc)' takes the latest 'off' in the sequence of 'off's
                -- to take the earliest use '(...order by id)'
                when 'off' then
                    ROW_NUMBER() over(partition by UserName, Reason,  OnOffSite, rn1 order by id desc)
                end,
                rn1
            from
            (
                select
                    *,
                    rn1 = ROW_NUMBER() over(partition by username, Reason,  order by id) +
                        ROW_NUMBER() over(partition by username, Reason, onoffsite order by id desc)
                from @t
            ) t
        ) t
        where rn2 = 1
    ) t1
    cross join
    (
        select k = 1 union select k = 2
    ) t2
    group by UserName, Reason, rn + k
) t
where timeon is not null or timeoff is not null
order by username
当OnOffSite=“off”时,我只记录一个原因。我认为问题在于,当OnOffSite=“on”时,Reason的值为NULL,但在这种情况下,我只想按时间戳分组,并使用“off”Reason作为值


这是SQL Server 2012

从分组中删除
原因
,并将第32行的
原因
替换为
Reason=max(当OnOffSite='on'然后null else Reason end时的情况)
使代码看起来像这样:

[...................................]

-- =====================
-- solution
-- =====================
select
    UserName, timeon, timeoff, diffinhours = DATEDIFF(hh, timeon, timeoff), reason
from
(
    select
        UserName,
        reason = max(case when OnOffSite = 'on' then null else Reason end),
        timeon = max(case when k = 2 and OnOffSite = 'on' then Time end),
        timeoff = max(case when k = 1 and OnOffSite = 'off' then Time end)
    from
    (
        select
            ID,
            UserName,
            OnOffSite,
            Time,
            rn = ROW_NUMBER() over(partition by username order by id),
            Reason

[...................................]

使用max和string并不完全是书本上讲的,但它应该适用于这种情况。

这看起来很有效,我将做一些测试,并将此标记为答案,谢谢!