Quantcast
Viewing all articles
Browse latest Browse all 10

Using a CTE to Allocate Tickets to Timeslots

SQL Server Common Table Expressions (CTEs) are most often used to solve problems such as paging and hierarchical queries, however in this post I want to demonstrate another use: booking of timeslots. If you were writing a system for an attraction with predefined timeslots, say to see the damper in the Taipei 101 building, you would need to be able to distribute the allocation of tickets over these timeslots. So if a group of 16 people arrived, depending on the space available in the timeslot they may be allocated over several timeslots and would have to patiently wait until their turn came around.

The most obvious way to solve this problem is to use a looping structure that moves through the timeslots, allocates the tickets and reduces the number of tickets available for that timeslot. Unfortunately to ensure that slots are not over booked while this is going on, one has to lock the tables affected by the allocation process. This can cause performance and concurrency issues as the number of requested tickets and therefore the lock duration increases. A more efficient and elegant solution is to use the inherent looping/recursive nature of a CTE to do this allocation in one step. So instead of doing a loop, insert into select, loop again cycle, the code can simply do a single insert into select statement to block out the allocated timeslots in one implicit transaction.

To demonstrate the approach, let us take a scenario where we want to allocate 16 tickets. The number of remaining places available per timeslot are as per the diagram below.

Image may be NSFW.
Clik here to view.
clip_image001

Our simplified database would therefore have a Timeslot table that contains the time and the running available capacity for each one, like this:

TimeAvailable Capacity
1 Jan 2008 08:00:000
1 Jan 2008 08:20:005
1 Jan 2008 08:40:000
1 Jan 2008 09:00:007
1 Jan 2008 09:20:002
1 Jan 2008 09:40:0010

We want to allocate 16 tickets across those timeslot. So the CTE we create should operate in the following manner:

Image may be NSFW.
Clik here to view.
clip_image002

The CTE to do this looks like this:

DECLARE @SeatsRequested SMALLINT

SET
@SeatsRequested = 16;

WITH
TimeSlotAllocation (Time, SeatsAllocated, SeatsLeftToAllocate) as
(
   
--Find the first time slot to use
   
SELECT TOP 1
       
Time,
        dbo.MinNumber(@SeatsRequested, AvailableCapacity)
as SeatsAllocated,
        @SeatsRequested - dbo.MinNumber(@SeatsRequested, AvailableCapacity)
as SeatsLeftToAllocate
   
FROM
       
Timeslot
   
WHERE
       
AvailableCapacity > 0
   
ORDER BY
       
Time
    
   
UNION ALL
    
   
--Sequentially find the other timeslots that can be used to fulfill the sale request
   
SELECT 
       
TS.Time,
        dbo.MinNumber(TSA.SeatsLeftToAllocate, TS.AvailableCapacity),
        TSA.SeatsLeftToAllocate - dbo.MinNumber(TSA.SeatsLeftToAllocate, TS.AvailableCapacity)
   
FROM
       
Timeslot TS
        
       
--Join on to the next timeslot
       
INNER JOIN TimeSlotAllocation TSA ON
           
TS.Time = DATEADD(MINUTE, 20, TSA.Time)
   
WHERE
       
SeatsLeftToAllocate > 0
)

You’ll notice the code relies on a user defined function, MinNumber which simply returns the minimum value of the two supplied parameters. As you can see the logic is pretty straight forward:

  1. Find the first available timeslot.
  2. Allocate the lesser of the number of SeatsLeftToAllocate or the available timeslot capacity.
  3. Store the number of tickets remaining in SeatsLeftToAllocate
  4. Move on to the next timeslot by adding the number of minutes between timeslots.
  5. Repeat steps 2 to 4 until there are no SeatsLeftToAllocate.

Of course the final solution would include other logic, such as bounding the allocation of timeslots by day and checking that all tickets had been allocated, but this is merely an illustration of an approach.

If you want to play around with a working example, here is the code.

Image may be NSFW.
Clik here to view.

Viewing all articles
Browse latest Browse all 10

Trending Articles