2014-09-30 2 views
2

를이는 SQL 데이터베이스 데이터는 다음과 같습니다 [UserCode] 0보다 뭔가 다른 경우SQL 수 일 연속

UserTable 

UserName | UserDate  | UserCode 
------------------------------------------- 
user1  | 08-31-2014 | 232 
user1  | 09-01-2014 | 232 
user1  | 09-02-2014 | 0 
user1  | 09-03-2014 | 121 
user1  | 09-08-2014 | 122 
user1  | 09-09-2014 | 0 
user1  | 09-10-2014 | 144 
user1  | 09-11-2014 | 166 
user2  | 09-01-2014 | 177 
user2  | 09-04-2014 | 188 
user2  | 09-05-2014 | 199 
user2  | 09-06-2014 | 0 
user2  | 09-07-2014 | 155 

는 (결과적으로) 연속 일 수를 계산해야한다. UserDate는 09-01-2014 및 09-11-2014 사이에 있습니다. Result가 2 이상인 경우에만 결과를 표시합니다. 내가 돌아 내 SQL 쿼리에 원하는 것은

은 다음과 같습니다

UserName | StartDate  | EndDate  | Result 
---------------------------------------------------------- 
user1  | 09-01-2014 | 09-03-2014 | 2 
user1  | 09-08-2014 | 09-11-2014 | 3 
user2  | 09-04-2014 | 09-07-2014 | 3 

는 SQL 쿼리를 사용이 가능합니까?

+1

당신이 사용하는 경우 MSSQL의 어떤 버전 그런 다음이 콜 럼에 의해 그룹은 당신이 원하는 요약을 얻을 수 있습니까? – Arion

답변

10

이것은 Gaps and Islands 문제입니다. 이 문제를 해결하는 가장 쉬운 방법은 순서의 차이를 식별 할 수 ROW_NUMBER()을 사용하고 있습니다 :

SELECT UserName, 
     UserDate, 
     UserCode, 
     GroupingSet = DATEADD(DAY, 
          -ROW_NUMBER() OVER(PARTITION BY UserName 
                 ORDER BY UserDate), 
          UserDate) 
FROM UserTable; 

이 제공 :이 연속 행에 대한 GroupingSet에서 상수 값을 제공합니다 볼 수 있듯이

UserName | UserDate  | UserCode | GroupingSet 
------------+---------------+------------+------------- 
user1  | 09-01-2014 | 1   | 08-31-2014  
user1  | 09-02-2014 | 0   | 08-31-2014  
user1  | 09-03-2014 | 1   | 08-31-2014  
user1  | 09-08-2014 | 1   | 09-04-2014  
user1  | 09-09-2014 | 0   | 09-04-2014  
user1  | 09-10-2014 | 1   | 09-04-2014  
user1  | 09-11-2014 | 1   | 09-04-2014  
user2  | 09-01-2014 | 1   | 08-31-2014  
user2  | 09-04-2014 | 1   | 09-02-2014  
user2  | 09-05-2014 | 1   | 09-02-2014  
user2  | 09-06-2014 | 0   | 09-02-2014  
user2  | 09-07-2014 | 1   | 09-02-2014  

.

WITH CTE AS 
( SELECT UserName, 
      UserDate, 
      UserCode, 
      GroupingSet = DATEADD(DAY, 
           -ROW_NUMBER() OVER(PARTITION BY UserName 
                  ORDER BY UserDate), 
           UserDate) 
    FROM UserTable 
) 
SELECT UserName, 
     StartDate = MIN(UserDate), 
     EndDate = MAX(UserDate), 
     Result = COUNT(NULLIF(UserCode, 0)) 
FROM CTE 
GROUP BY UserName, GroupingSet 
HAVING COUNT(NULLIF(UserCode, 0)) > 1 
ORDER BY UserName, StartDate; 

Example on SQL Fiddle

+0

고마워요.하지만 제 질문을 편집했습니다. 내 실수! UserCode가 항상 1이나 0이 아니기 때문에 나는 sum을 사용할 수 없다. – majukivi

+0

OK, 나는 그것을 단지 'SUM'에서 'COUNT (NULLIF (UserCode, 0))'로 변경 했으므로, 'UserCode'가'0 ' 'NULLIF' 함수는'NULL'으로 변환하고'COUNT'에 포함되지 않습니다. – GarethD

+0

감사합니다. 잘 했어!!! – majukivi

0

시도하십시오 :

;with T1 as(
    select 
     *, 
     ROW_NUMBER() over ( order by UserName, UserDate) ID 
    from tbl 
) 
,T as (
    SELECT *, 1 CNT FROM T1 where ID=1 
    union all 
    SELECT b.*, (case when T.UserDate+1=b.UserDate and 
          T.UserName=b.UserName then t.CNT 
         else T.CNT+1 end) 
    from T1 b INNER JOIN T on b.ID=T.ID+1 
) 
select distinct UserName, MIN(UserDate), max(UserDate) 
,sum(case UserCode when 0 then 0 else 1 end) From T group by UserName, CNT 
having COUNT(*)>1 

SQL Fiddle Demo

+0

고마워요.하지만 제 질문을 수정했습니다. 내 실수! UserCode가 항상 1이나 0이 아니기 때문에 나는 sum을 사용할 수 없었다. – majukivi