I have a table similar to the one shown. It contains a list of user ids, the hour value for each hour of the day and an Avail flag to determine if that user is available on that hour.
I need to list all User ids which are available for a number of consecutive hours defined as @n
#####################
# UID # Avail # Hour#
#####################
# 123 # 1 # 0 #
# 123 # 1 # 1 #
# 123 # 0 # 2 #
# 123 # 0 # 3 #
# 123 # 0 # 4 #
# 123 # 1 # 5 #
# 123 # 1 # 6 #
# 123 # 1 # 7 #
# 123 # 1 # 8 #
# 341 # 1 # 0 #
# 341 # 1 # 1 #
# 341 # 0 # 2 #
# 341 # 1 # 3 #
# 341 # 1 # 4 #
# 341 # 0 # 5 #
# 341 # 1 # 6 #
# 341 # 1 # 7 #
# 341 # 0 # 8 #
######################
This should result in the following output for @n=3
#######
# UID #
#######
# 123 #
#######
I have attempted to use the ROW_NUMBER() over (partition by UID,Avail ORDER BY UID,Hour) to assign a number to each row partitioned by the UID and Whether or not they are flagged as available. However this does not work as the periods of availability may change multiple times a day and the ROW_NUMBER() function was only keeping two counts per user based on the Avail flag.
5条答案
按热度按时间3htmauhk1#
If you're using SQL Server 2012+ you could using a windowed SUM, but you have to specify the number of rows in the window frame in advance as it won't accept variables so it's not that flexible:
If you want flexibility you could make it a stored procedure and use dynamic SQL to build and execute the statement, something like this:
and execute it using
execute testproc 3
An even more inflexible solution is to use correlated subqueries, but then you have to add another subquery for each added count:
And yet another way, using row_number to find islands and then filtering by sum of avail for each island:
l5tcr1uw2#
This works... It does a self join on userID and anything in 2nd table with in @n (3hr) then returns only those records having a count of 3 records.
http://sqlfiddle.com/#!6/f97ee
xxe27gdn3#
Didn't have time to polish this ... but this is one option.
Here is the sample data creation...
nwlls2ji4#
The main query with several CTE below give you several possibility in order to show what you need (max per user, user with N hours, etc.). Just update the last query below the CTE.
Create table and data:
Last row has been added to show that it can detect continuous hours around midnight (see back cte). i.e. 23 => 2AM for uid 341
Query MAX continous hours per user:
results:
Get user with at least 3 continuous hours (replace last select with this one):
Please not that I considered that (123, 1, 5) give 1 available hour from 5 to 6. Therefore 5 to 8 gives you 4 available hours from 5 to 9.
dxxyhpgq5#
SQL CODE
Output