There is one traditional and exciting thing at the end of every SQL Server meeting at our Atlanta based user group: the raffle! This is when the swag is handed out to the lucky winners. The method we have employed in the past was to get a roll of raffle tickets, the kind one can find at office supplies stores, and hand half of a ticket to meeting participants. We put the other half in a bag or box, shuffle the tickets in the box, and then started drawing them out. Usually the numbers on the tickets were long and hard to read, which added to the time the process took to complete.
The person(s) handling the raffles asked for the community to help find a better solution. This is when we designed this automated approach, the SQL-Server-way. The article presents the method employed, and also the scripts being used.
We begin (of course) by creating a database, called [RaffleDb]See scripts below:
------------------------------------------------------------ USE [master] GO -- IF EXISTS (SELECT name FROM sys.databases WHERE name = N'RaffleDb') DROP DATABASE [RaffleDb] GO -- IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'RaffleDb') BEGIN CREATE DATABASE [RaffleDb] END GO ------------------------------------------------------------
We continue by creating a table, called [Raffle], which will hold a random value string. The field [RaffleId] is an identity column and will hold a number from 1 to the total number of participants in the raffle. The field [Selected] is of a bit type and will be updated to 1 whenever the [RaffleId] is picked.
The stored procedure [RAFFLE_SETUP] (see below) contains the code to create the table above and to fill it up with a number of records equal to the number of raffle participants.
------------------------------------------------------------ USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_SETUP]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[RAFFLE_SETUP] GO -- IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_SETUP]') AND type in (N'P', N'PC')) BEGIN EXEC dbo.sp_executesql @statement = N'
CREATE PROCEDURE [dbo].[RAFFLE_SETUP](@Count int) AS BEGIN -- IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N''[dbo].[DF_Raffle_Selected]'') AND type = ''D'') BEGIN ALTER TABLE [dbo].[Raffle] DROP CONSTRAINT [DF_Raffle_Selected] END -- IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N''[dbo].[DF_Raffle_RandomValue]'') AND type = ''D'') BEGIN ALTER TABLE [dbo].[Raffle] DROP CONSTRAINT [DF_Raffle_RandomValue] END -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].[Raffle]'') AND type in (N''U'')) DROP TABLE [dbo].[Raffle] -- IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].[Raffle]'') AND type in (N''U'')) BEGIN CREATE TABLE [dbo].[Raffle]( [RaffleId] [int] IDENTITY(1,1) NOT NULL, [RandomValue] [char](36) NOT NULL, [Selected] [bit] NOT NULL, CONSTRAINT [PK_Raffle] PRIMARY KEY CLUSTERED ( [RaffleId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] END -- IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N''[dbo].[DF_Raffle_RandomValue]'') AND type = ''D'') BEGIN ALTER TABLE [dbo].[Raffle] ADD CONSTRAINT [DF_Raffle_RandomValue] DEFAULT (newid()) FOR [RandomValue] END -- IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N''[dbo].[DF_Raffle_Selected]'') AND type = ''D'') BEGIN ALTER TABLE [dbo].[Raffle] ADD CONSTRAINT [DF_Raffle_Selected] DEFAULT ((0)) FOR [Selected] END -- DECLARE @Counter int = 0 SET NOCOUNT ON WHILE @Counter < @Count BEGIN INSERT Raffle VALUES(DEFAULT, DEFAULT) SET @Counter = @Counter + 1 END SET NOCOUNT OFF -- END
' END GO ------------------------------------------------------------
To draw a number, use stored procedure [RAFFLE_DRAW] shown below:
------------------------------------------------------------ USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_DRAW]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[RAFFLE_DRAW] GO -- IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_DRAW]') AND type in (N'P', N'PC')) BEGIN EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[RAFFLE_DRAW] AS BEGIN DECLARE @RaffleId int SET NOCOUNT ON SELECT TOP 1 @RaffleId = RaffleId FROM Raffle WHERE Selected = 0 ORDER BY RandomValue IF @RaffleId IS NOT NULL BEGIN UPDATE Raffle SET Selected = 1 WHERE RaffleId = @RaffleId SELECT @RaffleId AS [Ticket #] END ELSE BEGIN PRINT ''All raffle tickets have been picked!'' END SET NOCOUNT OFF END' END GO ------------------------------------------------------------
Running [RAFFLE_DRAW] for each prize will pick the winning number and mark it as selected. This disallows that particular number to be picked again.
At any time during the raffle the stored procedure [RAFFLE_REVIEW] may be used to list all the drawn numbers in the order they were selected.
------------------------------------------------------------ USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_REVIEW]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[RAFFLE_REVIEW] GO -- IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_REVIEW]') AND type in (N'P', N'PC')) BEGIN EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[RAFFLE_REVIEW] AS BEGIN SELECT RaffleId AS [Ticket #] FROM Raffle WHERE Selected = 1 ORDER BY RandomValue END' END GO ------------------------------------------------------------
Scripts below show a sample run:
------------------------------------------------------------ -- SHUFFLE UP !!! ------------------------------------------------------------ -- USE [RaffleDb] GO -- RAFFLE_SETUP 37 GO -- --run a number of times equal to the number of raffle prizes RAFFLE_DRAW GO -- --run any time there is a need for review RAFFLE_REVIEW GO ------------------------------------------------------------
Additional scripts (shown below) may be used for cleanup.
------------------------------------------------------------ -- RAFFLE_CLEANUP ------------------------------------------------------------ -- USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_SETUP]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[RAFFLE_SETUP] GO ------------------------------------------------------------ USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_DRAW]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[RAFFLE_DRAW] GO ------------------------------------------------------------ USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[RAFFLE_REVIEW]') AND type in (N'P', N'PC')) DROP PROCEDURE [dbo].[RAFFLE_REVIEW] GO ------------------------------------------------------------ -- USE [RaffleDb] GO -- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Raffle]') AND type in (N'U')) DROP TABLE [dbo].[Raffle] GO -- ------------------------------------------------------------ -- USE [master] GO -- IF EXISTS (SELECT name FROM sys.databases WHERE name = N'RaffleDb') DROP DATABASE [RaffleDb] GO -- ------------------------------------------------------------ -- END ------------------------------------------------------------
This concludes our adventure in the magic world of raffles, showing a possible implementation for the amusement of SQL Server fans.