Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

sql server - SQL count consecutive days

This is the SQL database data:

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

Should only count consecutive days (as Result) if [UserCode] is something else than zero. UserDate is between 09-01-2014 and 09-11-2014. Show result only if Result is 2 or more.

What I want to my sql query to return is:

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

Is this possible using only SQL query?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is a Gaps and Islands problem. The easiest way to solve this is using ROW_NUMBER() to identify the gaps in the sequence:

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

This gives:

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    

As you can see this gives a constant value in GroupingSet for consecutive rows. You can then group by this colum to get the summary you want:

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...