SQL Server在不同的行之间找到datediff,sum

时间:2021-12-09 01:29:07

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。

2 个解决方案

#1


3  

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

#2


0  

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.

之后,我建议您在表中添加一个状态字段,用于记录每行的状态(匹配,不匹配,删除等)。每当添加一行时,您应该尝试匹配它以成对。成功匹配会将两行的状态设置为匹配,否则新行将不匹配。

#1


3  

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

#2


0  

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.

之后,我建议您在表中添加一个状态字段,用于记录每行的状态(匹配,不匹配,删除等)。每当添加一行时,您应该尝试匹配它以成对。成功匹配会将两行的状态设置为匹配,否则新行将不匹配。