2011-10-26 3 views
1

시간 추적 시스템에서 데이터를 분석하는 쿼리를 작성하려고합니다. 사용자가 스 와이프 할 때마다 스 와이프 시간과 켜짐 또는 꺼짐 사이트 (입력 또는 종료)를 기록하는 행을 만듭니다. 사용자 'Joe Bloggs'의 경우에는 4 개의 행이 있습니다.이 두 행을 조합하여 Joe Bloggs의 사이트에 소요 된 총 시간을 계산합니다.SQL Server는 다른 행 사이의 계산을 찾습니다.

문제는 페어링하기 쉽지 않은 레코드가 있다는 것입니다. 주어진 예제에서, 두 번째 사용자는 두 개의 연속 '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 | 

내 시스템은 MS SQL 2005입니다. 쿼리의보고 기간은 매월입니다.

누구든지 해결책을 제안 할 수 있습니까? 내 데이터는 사용자 이름과 시간별로 테이블에 이미 그룹화되어 있으며 ID 필드는 ID입니다.

+2

존스 이안 (Iones)에 대해 다음 중 어느 것을 드롭하고 싶습니까? –

+0

'사용자가 스 와이프 할 때마다'사용자가 인증 할 때마다 '를 의미합니까? – npclaudiu

+0

두 번째 'on'을 삭제하고 싶습니다. 스 와이프하여 인증한다는 의미입니다. 지금까지 해답을 주셔서 감사합니다 :) 나는 오늘 시험해 볼 것입니다. – MarcKirby

답변

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 
+0

이 답변은 정확하며 내 데이터와 잘 작동합니다. T-SQL 마스터가 있으며 그의 이름은 Alexey입니다! 많은 감사. – MarcKirby

+0

+1. 내 솔루션은 거의 동일했습니다. 처음부터 순위를 매겨 봤는데 어느 시점에서 중간 그룹을 순위로 변경했음을 알 수 있습니다. 남은 유일한 차이점은'timeon'과'timeoff'를 얻는 방법이었습니다 : 저는 자기 조인을 사용했습니다.이 경우에는 당신이 대답에 사용했던'max (case ...) '를 그룹화하는 것보다 나쁘다고 생각합니다. . 어쨌든, 이것은 잘 해내므로 ... 잘 했어! :) –

0

먼저 비즈니스 측면에서 대화하고 일련의 일치 규칙을 결정해야합니다.

그런 다음 각 행 (일치, 일치하지 않는 항목, 삭제 된 항목 등)의 상태를 기록하는 테이블에 상태 필드를 추가하는 것이 좋습니다. 행이 추가 될 때마다 쌍을 만들기 위해 일치시켜야합니다. 일치하는 항목이 있으면 두 행의 상태가 일치하도록 설정되고 그렇지 않으면 새 행이 일치하지 않게됩니다.