We're extracting booking information for our tennis courts from our SQL database into a simple results table to help us build a picture of court usage. It's pretty straight-forward except when it comes to bookings that last more than an hour.
At present, each booking results in a row in our results table. Each row contains a start-time, duration and court number. We'd like to map this table directly into a spreadsheet or pivot table so we can see how many hours our courts are booked and which hours of the day.
Currently, our SQL query looks something like:
INSERT INTO Results (year, month, day, hour, duration, court)
SELECT DATEPART (yy, b.StartDateTime),
DATEPART (mm, b.StartDateTime),
DATEPART (dd, b.StartDateTime),
DATEPART (hh, b.StartDateTime),
a.Duration,
a.Court
FROM Bookings b
INNER JOIN Activities a
ON b.ActivityID = a.ID
Our problem is that bookings for 2, 3 or more hours duration only have one row in the results table, ie. for the first hour of the booking. This is because the length of the booking is captured in the duration data. We could do some post-processing on the data to achieve our ends, but it would be easier if this was possible in our SQL query.
Can this query be modified in some way, such that depending on the duration (which can be 1, 2, 3, ... hours) the appropriate number of rows are inserted into the results table, each of duration 1. Thus a 3-hour booking starting at 9am, would results in three rows in the results table, one at 9am, one at 10am and one at 11am, each of duration 1-hour.
So instead of the following row in the results table:
Year, Month, Day, Hour, Duration, Court
2009, 08, 25, 09, 3, 1
we get the following rows:
Year, Month, Day, Hour, Duration, Court
2009, 08, 25, 09, 1, 1
2009, 08, 25, 10, 1, 1
2009, 08, 25, 11, 1, 1
This would make mapping the results table into a spreadsheet much easier.
UPDATE 2009-08-25: Of course, as the first couple of answers show, it doesn't have to be a single query. A set is fine.
UPDATE 2009-08-26: Have been side-tracked and haven't had a chance to try out the proposed solutions yet. Hope to do so soon and will select an answer based on the results.
UPDATE 2009-08-27: Finally got a chance to try out the solutions. The table of integers and joining to produce a solution was an eye-opener. Especially the use of cross-joins to create such a table. This is probably the cleaner, SQL way of doing things.
However, in the end, I went with Aaron's solution involving the flag and the simple algorithm. I did enhance it by wrapping his algorithm in a while loop to keep iterating until no durations > 1 were left. This was quick and easy to implement. It also highlighted that we did have some 10 hour bookings, so I didn't need to hard-code a limit here.
I should note that I incorporated Jeff's idea of max duration into the while loop counter, rather than my original idea of count the items with duration > 1. Slightly less code.