This is an example of when a "Number" table becomes very handy! If you are not familiar with this concept, read this blog post from Adam Machanic: You REQUIRE a Numbers Table
The numbers table is used to join to the Appointment Slots column (in this case) to duplicate each row AppointmentSlots number of times.
-- A simple recreation of your CTE data...
CREATE TABLE #AppointmentPeriods
(
AppointmentLocation CHAR(1),
AppointmentStartTime TIME,
AppointmentEndTime TIME,
AppointmentSlotsAvailable SMALLINT
)
INSERT INTO #AppointmentPeriods VALUES
('A', '09:00', '09:15', 2),
('A', '09:15', '09:30', 2),
('A', '09:30', '09:45', 2),
-- ....
('A', '16:30', '16:45', 2),
('A', '16:45', '17:00', 2),
('B', '09:00', '09:15', 1),
('B', '09:15', '09:30', 1),
('B', '09:30', '09:45', 1),
-- ....
('B', '16:30', '16:45', 1),
('B', '16:45', '17:00', 1)
-- Numbers table
CREATE TABLE #Numbers (NumberValue SMALLINT)
INSERT INTO #Numbers
-- TOP value should be changed so it is greater than the
-- maximum number of potential appointment slots any location can have
SELECT TOP 20
ROW_NUMBER() OVER (ORDER BY object_id)
FROM sys.objects
SELECT #AppointmentPeriods.*, NumberValue AS AppointmentSlotNumber
FROM #AppointmentPeriods
INNER JOIN #Numbers
ON AppointmentSlotsAvailable >= NumberValue
Query output:
Location | StartTime | EndTime | AppointmentSlots | SlotNumber
A | 09:00 | 09:15 | 2 | 1
A | 09:00 | 09:15 | 2 | 2
A | 09:15 | 09:30 | 2 | 1
A | 09:15 | 09:30 | 2 | 2
B | 16:30 | 16:45 | 1 | 1
B | 16:45 | 17:00 | 1 | 1
PS: There are many ways to generate a numbers table: SO: What is the best way to create and populate a numbers table?