Problem
Games are by nature fit for randomness, relying on chance like to roll dice, shuffling cards, spawning enemies, and others. Is it possible to use T-SQL to accomplish the randomness needed? Let’s see how we can create a SQL Server poker game using a random numbers generator process.
Solution
Developers often think SQL Server is only for CRUD operations, but the database engine has features for game logic, simulations, or gamification.
Randomization techniques are purely mathematical used to simulate unpredictability, and applied to sampling testing, simulations, load balancing, and security.
This tip is focused on gaming and entertainment to have fun, but you can realize that this logic can be used in real-world business problems too.
Poker Game
I decided to simulate a poker game with a random numbers generator. The basic rules of the game are using a 52-card deck, where you and the SQL Server will receive seven (7) cards and you need to drop two (2), to keep only five (5) in your hand.
I will use the common poker hands from the strongest to the weakest:
- Royal Flush: it is a special case of Straight Flush when finished with ‘A’ card.
- Straight Flush: five consecutive cards of the same suit
- Four of a Kind: four cards of the same rank
- Full House: three of a kind and a pair
- Flush: five cards of the same suit, not making a sequence
- Straight: five consecutive cards, any suits
- Three of a Kind: three cards of the same rank
- Two Pair: two different pairs
- One Pair: two cards of the same rank
- High Card: highest card wins if no hand above
SQL Solution with Permuted Congruential Generator
The Permuted Congruential Generator (PCG) takes a simple and fast random Congruential base generator and combines it with Permuted, which is the scramble part of the logic, that uses a permutation math trick to make the numbers look more random or evenly spread out. It is hard to guess the next number compared to other generators, but it is still not secure enough for serious cryptography.
Algorithms are used to produce a stream of numbers to match statistical expectations and I choose to work with PCG64.
Let´s create a function to generate the PCG 64 bits that will generate random number between @low and @high values. The @int1 and @int2 are random generated numbers that needs to be supplied to the function.
-- =============================================
-- Author: SCP - MSSQLTips
-- Create date: 20250813
-- Description: Permuted congruential generator
-- =============================================
CREATE OR ALTER FUNCTION [dbo].[ufnRndGenPCG64]
(@int1 bigint
,@int2 bigint
,@low float
,@high float)
RETURNS float
AS
BEGIN
DECLARE @low32 bigint = (@int1 + 2147483648);
DECLARE @high32 bigint = (@int2 + 2147483648);
DECLARE @u float = CONVERT(float, @high32 * 4294967296 + @low32) / 18446744073709551616.0;
DECLARE @result float = @low + (@high - @low) * @u;
RETURN @result;
END
GO
Let first have a look if this function, in the long run, it will take all the cards with similar frequency.
-- MSSQLTips (TSQL)
DECLARE @i int = 0
,@n int
,@t int = 10000;
DECLARE @Data
TABLE (Id int
,n int
,q int);
WHILE @i < @t BEGIN
SET @n = [dbo].[ufnRndGenPCG64] (CHECKSUM(NEWID()),CHECKSUM(NEWID()),1,53);
INSERT INTO @Data
VALUES(@i,@n,1)
SET @i += 1;
END
DECLARE @Summary
TABLE (n int
,freq float);
INSERT INTO @Summary
SELECT n
,CONVERT(decimal(10,2),COUNT(n) / (@t * 0.01)) AS Freq
FROM @Data
GROUP BY n
ORDER BY n;
SELECT AVG(freq) AS Mean
,STDEV(freq) AS Std
FROM @Summary;
GOI run it with different values of n and the expected output for any card is 1 in 52 which is 1 / 52 * 100 = 1.923076.
| n | mean | std |
|---|---|---|
| 10000 | 1.92 | 0.16 |
| 100000 | 1.92 | 0.05 |
| 1000000 | 1.92 | 0.02 |
I will not run a test of hypothesis to confirm because I am happy with it.
Tables
The first table will hold the deck of 52 cards
-- MSSQLTips (TSQL)
CREATE TABLE [dbo].[GamePoker](
[CardFace] [nvarchar](3) NOT NULL,
[CardId] [int] IDENTITY(1,1) NOT NULL,
[CardValue] [smallint] NULL,
[CardSuite] [nvarchar](10) NULL,
[CardHolder] [smallint] DEFAULT 0,
CONSTRAINT [PK_GamePoker] PRIMARY KEY CLUSTERED
(
[CardFace] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GOThe second table will hold the computational part of the game
-- MSSQLTips (TSQL)
CREATE TABLE [dbo].[GamePokerScore](
[Player] [int] NOT NULL,
[HighCard] [nvarchar](50) NULL,
[PairOne] [nvarchar](50) NULL,
[PairTwo] [nvarchar](50) NULL,
[ThreeOfAKind] [nvarchar](50) NULL,
[Straight] [nvarchar](50) NULL,
[Flush] [nvarchar](50) NULL,
[FullHouse] [nvarchar](50) NULL,
[FourOfAKind] [nvarchar](50) NULL,
[StraightFlush] [nvarchar](50) NULL,
[RoyalFlush] [nvarchar](50) NULL,
[Score] [float] DEFAULT 0,
CONSTRAINT [PK_GamePokerScore] PRIMARY KEY CLUSTERED
(
[Player] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GOUser Defined Functions
This function will retrieve the card value based on the card face.
-- =============================================
-- Author: SCP - MSSQLTips
-- Create date: 20250820
-- Description: Game Poker Card value check
-- =============================================
CREATE OR ALTER FUNCTION [dbo].[ufnGamePokerCardValue]
(@CardFace nvarchar(3))
RETURNS smallint
AS
BEGIN
DECLARE @cardValue int = 0;
SELECT @cardValue = [CardValue]
FROM [dbo].[GamePoker]
WHERE [CardFace] LIKE '%' + TRIM(@CardFace) + '%';
RETURN @cardValue;
END
GOThe second function will be used to identify a sequence of cards.
-- =============================================
-- Author: SCP - MSSQLTips
-- Create date: 20250820
-- Description: Game Poker Straight check
-- =============================================
CREATE OR ALTER FUNCTION [dbo].[ufnGamePokerStraigh]
(@Player int)
RETURNS nvarchar(25)
AS
BEGIN
DECLARE @face nvarchar(20)
,@straight nvarchar(25)
,@suite nvarchar(10)
,@suitePrevious nvarchar(10) = ''
,@cvNext int = 0
,@seq smallint = 0
,@seqSuite smallint
,@seqFace nvarchar(20) = '';
DECLARE crsStraight CURSOR FAST_FORWARD READ_ONLY FOR
SELECT [CardHolder] AS pl
,IIF(([CardValue] - LEAD([CardValue],1,0) OVER (ORDER BY [CardValue] DESC)) = 1 OR
([CardValue] - LEAD([CardValue],1,0) OVER (ORDER BY [CardValue] DESC)) = [CardValue],1,0) AS cvNext
,[CardFace] AS cf
,[CardSuite] AS cs
FROM [dbo].[GamePoker]
WHERE [CardHolder] = @Player
ORDER BY [CardHolder]
,[CardValue] DESC;
OPEN crsStraight
FETCH NEXT FROM crsStraight
INTO @player,@cvNext,@face,@suite;
WHILE @@FETCH_STATUS = 0 BEGIN
IF @cvNext = 1 BEGIN
SET @seqFace = @face + ' ' + @seqFace;
SET @seq += 1;
IF @suite = @suitePrevious
SET @seqSuite += 1;
ELSE BEGIN
SET @seqSuite = 1;
SET @suitePrevious = @suite;
END
END ELSE IF @cvNext <> 1 BEGIN
SET @seqFace = '';
SET @seq = 0;
END
IF @seq = 5 BEGIN
IF @seqSuite = 5
SET @straight = 'F' + @seqFace;
ELSE
SET @straight = @seqFace;
BREAK;
END
FETCH NEXT FROM crsStraight
INTO @player,@cvNext,@face,@suite;
END
CLOSE crsStraight;
DEALLOCATE crsStraight;
RETURN @straight;
END
GOStored Procedures
This stored procedure will deal the cards and will initiate the deck of cards if it was not already done.
-- =============================================
-- Author: SCP - MSSQLTips
-- Create date: 20250819
-- Description: Game Poker - Deal the cards
-- =============================================
CREATE OR ALTER PROCEDURE [dbo].[uspGamePokerDeal]
WITH EXECUTE AS CALLER
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;
IF (SELECT COUNT(*) FROM [dbo].[GamePoker]) <> 52 BEGIN
TRUNCATE TABLE [dbo].[GamePoker]
INSERT INTO [dbo].[GamePoker]
([CardFace]
,[CardValue])
VALUES (' A',14),(' 2', 2),(' 3', 3),(' 4',4),(' 5', 5)
,(' 6', 6),(' 7', 7),(' 8', 8),(' 9',9),('10',10)
,(' J',11),(' Q',12),(' K',13);
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 1
,[CardFace] += N'♥'
,[CardSuite] = 'Hearts'
WHERE [CardHolder] = 0;
INSERT INTO [dbo].[GamePoker]
([CardFace]
,[CardValue])
VALUES (' A',14),(' 2', 2),(' 3', 3),(' 4',4),(' 5', 5)
,(' 6', 6),(' 7', 7),(' 8', 8),(' 9',9),('10',10)
,(' J',11),(' Q',12),(' K',13);
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 1
,[CardFace] += N'♦'
,[CardSuite] = 'Diamonds'
WHERE [CardHolder] = 0;
INSERT INTO [dbo].[GamePoker]
([CardFace]
,[CardValue])
VALUES (' A',14),(' 2', 2),(' 3', 3),(' 4',4),(' 5', 5)
,(' 6', 6),(' 7', 7),(' 8', 8),(' 9',9),('10',10)
,(' J',11),(' Q',12),(' K',13);
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 1
,[CardFace] += N'♣'
,[CardSuite] = 'Clubs'
WHERE [CardHolder] = 0;
INSERT INTO [dbo].[GamePoker]
([CardFace]
,[CardValue])
VALUES (' A',14),(' 2', 2),(' 3', 3),(' 4',4),(' 5', 5)
,(' 6', 6),(' 7', 7),(' 8', 8),(' 9',9),('10',10)
,(' J',11),(' Q',12),(' K',13);
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 1
,[CardFace] += N'♠'
,[CardSuite] = 'Spades'
WHERE [CardHolder] = 0;
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 0;
END
-- PLAYER ====================================
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 0
WHERE [CardHolder] > 0;
DECLARE @i int = 0
,@n int = 0
,@h int = 0;
WHILE @i < 7 BEGIN
SET @n = [dbo].[ufnRndGenPCG64] (CHECKSUM(NEWID()),CHECKSUM(NEWID()),1,53);
IF EXISTS
(SELECT 1
FROM [dbo].[GamePoker]
WHERE [CardId] = @n AND
[CardHolder] = 0) BEGIN
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 1
WHERE [CardId] = @n;
SET @i += 1;
END
END
-- SQL =======================================
SET @i = 0;
WHILE @i < 7 BEGIN
SET @n = [dbo].[ufnRndGenPCG64] (CHECKSUM(NEWID()),CHECKSUM(NEWID()),1,53);
IF EXISTS
(SELECT 1
FROM [dbo].[GamePoker]
WHERE [CardId] = @n AND
[CardHolder] = 0) BEGIN
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 2
WHERE [CardId] = @n;
SET @i += 1;
END
END
COMMIT TRANSACTION;
SELECT [CardId]
,[CardFace]
,CONCAT([CardValue],' ',[CardSuite]) AS [CardName]
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1
ORDER BY [CardValue];
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION;
END
-- Print error information.
PRINT 'Error: ' + CONVERT(varchar(50), ERROR_NUMBER()) +
', Severity: ' + CONVERT(varchar(5), ERROR_SEVERITY()) +
', State: ' + CONVERT(varchar(5), ERROR_STATE()) +
', Procedure: ' + ISNULL(ERROR_PROCEDURE(), '-') +
', Line: ' + CONVERT(varchar(5), ERROR_LINE());
PRINT ERROR_MESSAGE();
END CATCH;
END
GO
This is the store procedure with the logic of the game to identify the cards and winner.
-- =============================================
-- Author: SCP - MSSQLTips
-- Create date: 20250819
-- Description: Game Poker - Scores
-- =============================================
CREATE OR ALTER PROCEDURE [dbo].[uspGamePokerScores]
WITH EXECUTE AS CALLER
AS
BEGIN
SET NOCOUNT ON;
IF NOT
(SELECT COUNT(*)
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1) = 5 BEGIN
PRINT 'The player does not have five cards set!';
RETURN
END;
TRUNCATE TABLE [dbo].[GamePokerScore];
INSERT INTO [dbo].[GamePokerScore]
([Player])
VALUES (1),(2);
-- Scoring ===========================================
DECLARE @player int
,@value int
,@score int
,@hand nvarchar(50)
,@face nvarchar(50);
DECLARE crsScore CURSOR FAST_FORWARD READ_ONLY FOR
SELECT [CardHolder] AS player
,[CardValue] AS cValue
,COUNT([CardValue]) AS score
,STRING_AGG([CardFace],' ')
WITHIN GROUP (ORDER BY [CardValue] ASC) AS hand
FROM [dbo].[GamePoker]
WHERE [CardHolder] > 0
GROUP BY [CardHolder]
,[CardValue]
ORDER BY 1,3,2 DESC;
OPEN crsScore
FETCH NEXT FROM crsScore
INTO @player,@value,@score,@hand;
WHILE @@FETCH_STATUS = 0 BEGIN
-- High Card
UPDATE [dbo].[GamePokerScore]
SET [HighCard] = IIF([Score] < @value,TRIM(LEFT(@hand,3)),[HighCard])
,[Score] = IIF([Score] < @value,@value,[Score])
WHERE [Player] = @player;
-- Pairs
IF @score = 2 AND
(SELECT [PairOne]
FROM [dbo].[GamePokerScore]
WHERE [Player] = @player) IS NULL
UPDATE [dbo].[GamePokerScore]
SET [PairOne] = @hand
,[Score] += [dbo].[ufnGamePokerCardValue] (LEFT(@hand,3))
WHERE [Player] = @player;
ELSE IF @score = 2
UPDATE [dbo].[GamePokerScore]
SET [PairTwo] = @hand
,[Score] += [dbo].[ufnGamePokerCardValue] (LEFT(@hand,3))
WHERE [Player] = @player;
-- Three of a kind and Full house
IF @score = 3 AND
(SELECT [PairOne]
FROM [dbo].[GamePokerScore]
WHERE [Player] = @player) IS NULL
UPDATE [dbo].[GamePokerScore]
SET [ThreeOfAKind] = @hand
,[Score] += [dbo].[ufnGamePokerCardValue] (LEFT(@hand,3))
WHERE [Player] = @player;
ELSE IF @score = 3
UPDATE [dbo].[GamePokerScore]
SET [FullHouse] = [PairOne] + ' ' + @hand
,[PairOne] = NULL
,[PairTwo] = NULL
,[Score] = [dbo].[ufnGamePokerCardValue] (LEFT([PairOne],3)) +
[dbo].[ufnGamePokerCardValue] (LEFT(@hand,3))
WHERE [Player] = @player;
-- Four of a kind
IF @score = 4
UPDATE [dbo].[GamePokerScore]
SET [FourOfAKind] = @hand
,[Score] += [dbo].[ufnGamePokerCardValue] (LEFT(@hand,3))
WHERE [Player] = @player;
FETCH NEXT FROM crsScore
INTO @player,@value,@score,@hand;
END
CLOSE crsScore;
DEALLOCATE crsScore;
-- Flush =============================================
-- five cards of same suit but not consecutive
WITH cteCards AS
(SELECT [CardHolder] AS ch
,COUNT([CardSuite]) AS cv
,STRING_AGG([CardFace],' ')
WITHIN GROUP (ORDER BY [CardValue] ASC) AS hand
FROM [dbo].[GamePoker]
WHERE [CardHolder] > 0
GROUP BY [CardHolder]
,[CardSuite]
HAVING COUNT([CardSuite]) > 4)
UPDATE [dbo].[GamePokerScore]
SET [Flush] = hand
,[PairOne] = NULL
FROM cteCards
WHERE [Player] = ch;
-- Straight low ======================================
-- five consecutive cards starting with A
SET @face = [dbo].[ufnGamePokerStraigh] (1);
UPDATE [dbo].[GamePokerScore]
SET [Straight] = @face
WHERE [Player] = 1;
IF @face IS NULL BEGIN
UPDATE [dbo].[GamePoker]
SET [CardValue] = 1
WHERE [CardValue] = 14;
UPDATE [dbo].[GamePokerScore]
SET [Straight] = [dbo].[ufnGamePokerStraigh] (1)
WHERE [Player] = 1;
UPDATE [dbo].[GamePoker]
SET [CardValue] = 14
WHERE [CardValue] = 1;
END
SET @face = [dbo].[ufnGamePokerStraigh] (2);
UPDATE [dbo].[GamePokerScore]
SET [Straight] = @face
WHERE [Player] = 2;
IF @face IS NULL BEGIN
UPDATE [dbo].[GamePoker]
SET [CardValue] = 1
WHERE [CardValue] = 14;
UPDATE [dbo].[GamePokerScore]
SET [Straight] = [dbo].[ufnGamePokerStraigh] (2)
WHERE [Player] = 2;
UPDATE [dbo].[GamePoker]
SET [CardValue] = 14
WHERE [CardValue] = 1;
END
UPDATE [dbo].[GamePokerScore]
SET [HighCard] = RIGHT([Straight],3)
,[Score] = [dbo].[ufnGamePokerCardValue] (RIGHT([Straight],3))
,[PairOne] = NULL
WHERE [Straight] IS NOT NULL;
UPDATE [dbo].[GamePokerScore]
SET [HighCard] = RIGHT([Flush],3)
,[Score] = [dbo].[ufnGamePokerCardValue] (RIGHT([Flush],3))
,[PairOne] = NULL
WHERE [Flush] IS NOT NULL;
-- Straight Flush ====================================
-- five consecutive cards of the same suit
UPDATE [dbo].[GamePokerScore]
SET [StraightFlush] = REPLACE([Straight],'F','')
,[Straight] = NULL
,[Flush] = NULL
WHERE [Straight] IS NOT NULL AND
[Straight] LIKE 'F%';
UPDATE [dbo].[GamePokerScore]
SET [Straight] = NULL
WHERE [Straight] IS NOT NULL AND
[Flush] IS NOT NULL;
-- Royal Flush =======================================
-- five consecutive cards of the same suit ending with A
UPDATE [dbo].[GamePokerScore]
SET [RoyalFlush] = [StraightFlush]
,[StraightFlush] = NULL
,[Straight] = NULL
,[Flush] = NULL
WHERE [StraightFlush] IS NOT NULL AND
[StraightFlush] LIKE '%A__';
-- Two pairs =========================================
UPDATE [dbo].[GamePokerScore]
SET [PairTwo] += ' ' + [PairOne]
,[PairOne] = NULL
WHERE [PairTwo] IS NOT NULL;
-- Winner ============================================
DECLARE @ScoreBoard
TABLE ([Id] int IDENTITY
,[Player] nvarchar(50)
,[Hand] nvarchar(1000)
,[Score] int);
INSERT INTO @ScoreBoard
SELECT CASE WHEN [Player] = 1
THEN 'You'
ELSE 'SQL'
END AS [Player]
,CONCAT( 'High card: ' + [HighCard] + ' and '
,'One Pair: ' + [PairOne]
,'Two Pair: ' + [PairTwo]
,'Three of a Kind: ' + [ThreeOfAKind]
,'Straight: ' + RIGHT([Straight],20)
,'Flush: ' + RIGHT([Flush],20)
,'Full House: ' + [FullHouse]
,'Four of a Kind: ' + [FourOfAKind]
,'Straight Flush: ' + RIGHT([StraightFlush],20)
,'Royal Flush: ' + RIGHT([RoyalFlush],20)) AS [Hand]
,[Score] + IIF([PairOne] IS NULL,0,POWER(2,5))
+ IIF([PairTwo] IS NULL,0,POWER(2,6))
+ IIF([ThreeOfAKind] IS NULL,0,POWER(2,7))
+ IIF([Straight] IS NULL,0,POWER(2,8))
+ IIF([Flush] IS NULL,0,POWER(2,9))
+ IIF([FullHouse] IS NULL,0,POWER(2,10))
+ IIF([FourOfAKind] IS NULL,0,POWER(2,11))
+ IIF([StraightFlush] IS NULL,0,POWER(2,12))
+ IIF([RoyalFlush] IS NULL,0,POWER(2,13)) AS [Score]
FROM [dbo].[GamePokerScore]
ORDER BY 3 DESC;
DECLARE @MaxScore float = (SELECT MAX([Score]) FROM @ScoreBoard);
UPDATE @ScoreBoard
SET [Player] += ' are the WINNER!!!'
WHERE [Score] = @MaxScore;
SELECT [Player]
,[Hand]
,[Score]
FROM @ScoreBoard;
END
GOThe final one is used to drop two cards and then execute the scoring.
-- =============================================
-- Author: SCP - MSSQLTips
-- Create date: 20250819
-- Description: Game Poker - Drop cards
-- =============================================
CREATE OR ALTER PROCEDURE [dbo].[uspGamePokerDrop]
(@Card1 int
,@Card2 int)
WITH EXECUTE AS CALLER
AS
BEGIN
SET NOCOUNT ON;
IF (SELECT COUNT(*)
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1) = 5 BEGIN
SELECT 'You must keep five cards!' AS [Constraint]
,STRING_AGG(CONVERT(nchar(5),[CardFace]),' ') WITHIN GROUP (ORDER BY [CardValue] ASC) AS [YourHand]
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1;
RETURN
END
BEGIN TRANSACTION;
UPDATE [dbo].[GamePoker]
SET [CardHolder] = 0
WHERE [CardId] IN (@Card1,@Card2) AND
[CardHolder] = 1;
IF (SELECT COUNT(*)
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1) < 5 BEGIN
PRINT('You must keep five cards!')
ROLLBACK TRANSACTION;
END ELSE
COMMIT TRANSACTION;
IF (SELECT COUNT(*)
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1) = 5
EXECUTE [dbo].[uspGamePokerScores]
ELSE
SELECT [CardId]
,[CardFace]
,CONCAT([CardValue],' ',[CardSuite]) AS [CardName]
FROM [dbo].[GamePoker]
WHERE [CardHolder] = 1
ORDER BY [CardValue];
END
GOPlaying the Game
Step 1 – get cards
The first step is to execute:
-- MSSQLTips (TSQL)
EXECUTE [dbo].[uspGamePokerDeal];
GOResulting in

Step 2 – drop 2 cards
If I do not want to continue due to a poor hand, just execute step 1 again, but I will go with my pair of eights. To continue I need to discard the two of clubs (28) and the four of hearts (4), where in the parenthesis is the Card Id. If you execute this command twice you are going to receive a message that you need to keep five cards.
-- MSSQLTips (TSQL)
EXECUTE [dbo].[uspGamePokerDrop] 28,4;
GOResulting in

And this time I win with a pair of eights!
If you need to show the score again, run the following:
-- MSSQLTips (TSQL)
EXECUTE [dbo].[uspGamePokerScores]
GOTo continue to play just execute the steps 1 and 2, as you wish.
Have fun!
Next Steps
- It is possible that I did not cover all possibilities and you can find a flaw on the scores, but the idea is there.
- One improvement is to save the history of games to train the computer to mimic a real player, adding a bet values step.
- I did not delete the computers extra cards to mimic what we did, looking at the cards and keeping the best ones.

Sebastião Pereira has over 40 years of experience in database development including T-SQL, algorithm design, machine learning and bringing innovative mathematical formulas to SQL Server. He started his career at a transnational fast-moving consumer goods (FMCG) company as an employee then later transitioning into a consultant role. He eventually founded his own company to develop software solutions for the healthcare industry. Sebastião is a respected award-winning author on MSSQLTips.com extending SQL Server capabilities beyond traditional workloads.
- MSSQLTips Awards
- Author of the Year – 2025
- Trendsetter (25+ tips) – 2025
- Rookie of the Year – 2024


