SQL Server find datediff between different rows, sum

后端 未结 2 913
南方客
南方客 2021-01-24 16:59

I am trying to build a query that analyzes data in our time tracking system. Every time a user swipes in or out, it makes a row recording the swipe time and On or Off site (entr

2条回答
  •  生来不讨喜
    2021-01-24 17:21

    -- =====================
    -- sample data
    -- =====================
    declare @t table
    (
        ID int,
        Time datetime,
        OnOffSite varchar(3),
        UserName varchar(50)
    )
    
    insert into @t values(123, '2011-10-25 09:00:00.000', 'on', 'Bloggs Joe')
    insert into @t values(124, '2011-10-25 12:00:00.000', 'off', 'Bloggs Joe')
    insert into @t values(125, '2011-10-25 13:00:00.000', 'on', 'Bloggs Joe')
    insert into @t values(126, '2011-10-25 17:00:00.000', 'off', 'Bloggs Joe')
    insert into @t values(127, '2011-10-25 09:00:00.000', 'on', 'Jonesy Ian')
    insert into @t values(128, '2011-10-25 10:00:00.000', 'on', 'Jonesy Ian')
    insert into @t values(129, '2011-10-25 11:00:00.000', 'off', 'Jonesy Ian')
    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')
    
    -- =====================
    -- solution
    -- =====================
    select
        UserName, timeon, timeoff, diffinhours = DATEDIFF(hh, timeon, timeoff)
    from
    (
        select
            UserName,
            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)
            from
            (
                select
                    ID,
                    UserName,
                    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, 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, OnOffSite, rn1 order by id desc)
                    end,
                    rn1
                from
                (
                    select
                        *,
                        rn1 = ROW_NUMBER() over(partition by username order by id) +
                            ROW_NUMBER() over(partition by username, 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, rn + k
    ) t
    where timeon is not null or timeoff is not null
    order by username
    

提交回复
热议问题