Bluedog67

Random Thoughts About SQL Server and My Dog Blue

About Bluedog67

My name is Stephen Horne. I am a well-trained owner of an Australian Cattle Dog named Blue. I also develop software mainly using SQL Server, ASP.NET, and C#. I love data, databases, T-SQL, and turning raw data into actionable information. My plan for this blog is to write about SQL Server and sometimes my dog Blue. Please contact me at stephen at bluedog67 dot com. Follow me on Twitter at bluedog67.

Yet Another FizzBuzz Solution: This Time Using T-SQL CTE (Common Table Expression) and spt_values

Insomnia triumphs over all. Sleep schedule is whacked. Saw this tweet from Jeff Atwood (Blog|Twitter) that referenced his post entitled "Why Can't Programmers.. Program?" located here. I thought I would accept the FizzBuzz challenge and try and program something in Transact-SQL.

Following is my attempt developed and tested on SQL Server 2008 Dev Ed. This solution uses a recursive CTE (Common Table Expression). You can find tons more about recursive CTEs here.

Please note that I know that CASE statement logic could be simplified - you can rely on WHEN expression order for evaluating which THEN clause is used for a given row. My preference is that with IF ELSE ELSE structures that the options be mutually exclusive.

;WITH cteCounter(number)
AS
(
SELECT 1 number
UNION ALL
SELECT (cteCounter.number + 1)  number
FROM cteCounter
WHERE (cteCounter.number + 1) <= 100
)
-- Switch out the SELECT clauses to see basic recursive CTE behavior and possible FizzBuzz solution.
-- SELECT cteCounter.number
SELECT CASE WHEN ((cteCounter.number % 3 = 0) AND (cteCounter.number % 5 = 0)) THEN 'FizzBuzz'
            WHEN ((cteCounter.number % 3 = 0) AND (cteCounter.number % 5 <> 0)) THEN 'Fizz'
            WHEN ((cteCounter.number % 3 <> 0) AND (cteCounter.number % 5 = 0)) THEN 'Buzz'
            ELSE CAST(cteCounter.number AS varchar(8)) END number
FROM cteCounter
ORDER BY cteCounter.number;

Dave Ballantyne (Blog|Twitter) publicly shamed me on Twitter for using a CTE to generate a range of number - thanks Dave <grin>! He rightly suggested using master.dbo.spt_values instead. I swore I would never use a CTE to implement a range of numbers! Following is the updated code.

SELECT CASE WHEN ((V.number % 3 = 0) AND (V.number % 5 = 0)) THEN 'FizzBuzz'
            WHEN ((V.number % 3 = 0) AND (V.number % 5 <> 0)) THEN 'Fizz'
            WHEN ((V.number % 3 <> 0) AND (V.number % 5 = 0)) THEN 'Buzz'
            ELSE CAST(V.number AS varchar(8)) END number
FROM master.dbo.spt_values V
WHERE V.type = 'P'
AND V.number between 1 and 100
ORDER BY V.number;

Categories: SQL Server
Permalink | Comments (1) | Post RSSRSS comment feed

Comments

Tom Spain

Monday, February 22, 2010 9:55 AM

Tom

Interesting.  First a recursive CTE to produce the number list - it's better than a loop, maybe worse than some other things.
Then a switch tousing the number column from master.dbo.spt_values: good job you've got the low number (100) version of the problem and do care whether your answer is scalable - at least with the recursive CTE the thing would work for whatever number; with master.dbo.spt_values it blows up at 2049!