This is my first attempt at short Transact-SQL videos. I was answering a question on a SQL Server related Facebook group. The question was about generating four-letter codes containing all possible combinations of letters A-Z. There are 26 letters in the english alphabet. Meaning the T-SQL code should generate 26^4 rows, or 456,976 rows.
I immediately thought this is great fit for a Tally Table solution (Read more in this article by Jeff Moden on SQL Server Central: The “Numbers” or “Tally” Table: What it is and how it replaces a loop – SQLServerCentral). And also that it would be a nice fit or a quick demo-video.
So first of all, here’s the video.
But I worked a bit further on the solution, and created a stored procedure which with parameters can create any length strings for the codes and also persist the data in a table instead of returning the rows to the caller.
What I’ve done is generate a string with SQL-code, based on the parameters, and then execute the SQL-code with the system stored procedure sys.sp_executesql.
CREATE OR ALTER PROC dbo.GenerateLetterStrings ( @LetterCount TINYINT, @ResultTable NVARCHAR(128) = NULL ) AS BEGIN SET NOCOUNT ON; DECLARE @sql NVARCHAR(MAX) = N' WITH alphabet AS ( SELECT CHAR(ASCII(''A'')+ ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) -1) AS n FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(n) )SELECT <<selectlist>> AS word <<intoclause>> FROM alphabet AS t0 <<crossjoin>> ' ; DECLARE @SelectList NVARCHAR(MAX) = N't0.n', @CrossJoin NVARCHAR(MAX) = N''; WITH eight AS (SELECT n FROM ( VALUES (1), (1), (1), (1), (1), (1), (1), (1) ) t (n) ), twofiftysix AS (SELECT TOP (@LetterCount - 1) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM eight CROSS JOIN eight e2 ORDER BY 1) SELECT @CrossJoin = @CrossJoin + CONCAT('CROSS JOIN alphabet as t', n, ' '), @SelectList = @SelectList + CONCAT('+t', n, '.n') FROM twofiftysix; SET @sql = REPLACE(@sql, N'<<selectlist>>', @SelectList); SET @sql = REPLACE(@sql, N'<<crossjoin>>', @CrossJoin); SET @sql = REPLACE(@sql, N'<<intoclause>>', COALESCE(N'INTO ' + @ResultTable, N'')); EXEC sys.sp_executesql @sql; END;
2 Replies to “Video and Stored Procedure: Generate N-length codes with T-SQL and a Tally Table”
Nicely done, Magnus. And thank you for the honorable mention.
If you really want to make an impact on this, show the performance (rather, the lack of) using nested WHILE loops and then an rCTE (recursive CTE) to replace the “alphabet” CTE.
Thanks Jeff. Yeah, I just played with it, so I will probably make another video to show the difference.
But I can share my initial findings already: The rCTE performs the worst when I compare them, with an elapsed time of more than three seconds for four-letter codes. The while-loop-approach returns in 1,7 seconds.