简体   繁体   English

SQL Server在不同行之间查找datediff,求和

[英]SQL Server find datediff between different rows, sum

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 (entry or exit). 每次用户向内或向外滑动时,都会记录记录滑动时间以及“打开”或“关闭”站点(进入或退出)。 In user 'Joe Bloggs' case there are 4 rows, which I want to pair and calculate a total time spent on site for Joe Bloggs. 在用户“ Joe Bloggs”的情况下,有4行,我想配对并计算出Joe Bloggs在网站上花费的总时间。

The problem is that there are records that are not as easy to pair. 问题是有些记录不容易配对。 In the example given, the second user has two consecutive 'on's, and I need to find a method for ignoring repeated 'on' or 'off' rows. 在给定的示例中,第二个用户有两个连续的“ on”,我需要找到一种忽略重复的“ on”或“ off”行的方法。

ID  | Time                    |OnOffSite| UserName   
------------------------------------------------------
123 | 2011-10-25 09:00:00.000 | on      | Bloggs Joe |
124 | 2011-10-25 12:00:00.000 | off     | Bloggs Joe |
125 | 2011-10-25 13:00:00.000 | on      | Bloggs Joe |
126 | 2011-10-25 17:00:00.000 | off     | Bloggs Joe |
127 | 2011-10-25 09:00:00.000 | on      | Jonesy Ian |
128 | 2011-10-25 10:00:00.000 | on      | Jonesy Ian |
129 | 2011-10-25 11:00:00.000 | off     | Jonesy Ian |
130 | 2011-10-25 12:00:00.000 | on      | Jonesy Ian |
131 | 2011-10-25 15:00:00.000 | off     | Jonesy Ian |

My System is MS SQL 2005. The reporting period for the query is Monthly. 我的系统是MS SQL 2005.查询的报告周期为每月。

Can anyone suggest a solution? 谁有人建议解决方案? my data is already grouped in a table by Username and time, with the ID field being Identity. 我的数据已按用户名和时间分组在表中,ID字段为Identity。

-- =====================
-- 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

First you need to talk with the business side and decide on a set of matching rules. 首先,您需要与业务方面进行讨论,并确定一组匹配的规则。

After that I suggest that you add a status field to the table where you record the status of each row (matched, unmatched, deleted etc). 之后,我建议您在表中添加一个状态字段,在其中记录每行的状态(匹配,不匹配,已删除等)。 Whenever a row is added you should try to match it to make a pair. 每当添加一行时,您应该尝试匹配它以成对。 A successful match sets the status of both rows to matched, otherwise the new row will be unmatched. 成功匹配会将两行的状态设置为匹配,否则新行将不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM