FizzBuzz

  • J.Faehrmann (2/22/2010)


    Gsquared your "ultimate version" is much fun to read!

    Now you only need to tell Jeff that you always code like that 😛

    Won't work. Jeff knows my coding too well.

    He's well aware that I'm more likely to really use something like this:

    DECLARE @Msg VARCHAR(1000) ;

    SELECT @Msg = COALESCE(@Msg + '

    ' + CASE WHEN Number % 3 = 0

    AND Number % 5 = 0 THEN 'BizzBuzz'

    WHEN Number % 3 = 0 THEN 'Bizz'

    WHEN Number % 5 = 0 THEN 'Buzz'

    ELSE CAST(Number AS VARCHAR(5))

    END, CASE WHEN Number % 3 = 0

    AND Number % 5 = 0 THEN 'BizzBuzz'

    WHEN Number % 3 = 0 THEN 'Bizz'

    WHEN Number % 5 = 0 THEN 'Buzz'

    ELSE CAST(Number AS VARCHAR(5))

    END)

    FROM Common.dbo.Numbers

    WHERE Number BETWEEN 1 AND 100 ;

    PRINT @Msg ;

    If we disregard the requirement that it's to print the output, and allow for either a dataset, or changing the output method to Text instead of a data grid, it gets even simpler:

    SELECT CASE WHEN Number % 3 = 0

    AND Number % 5 = 0 THEN 'BizzBuzz'

    WHEN Number % 3 = 0 THEN 'Bizz'

    WHEN Number % 5 = 0 THEN 'Buzz'

    ELSE CAST(Number AS VARCHAR(5))

    END AS BizzBuzzTest

    FROM Common.dbo.Numbers

    WHERE Number BETWEEN 1 AND 100

    ORDER BY Number ;

    This, of course, operates on the assumption that I've got a database named "Common" with a Numbers table in it. Since that's one of the first tools I set up for myself when working on a server, that assumption is valid enough. Without that, I'll have to set up either a temp table, or whatever else would be allowed on the server I'm working on.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Steve Cullen (2/22/2010)


    If you're going to setup your table with a while loop, just for a set-based solution, wouldn't the direct while loop be quicker without the table? Such as :

    declare @i int

    select @i = 1

    while @i <= 100

    begin

    if (@i % 3 = 0) and (@i % 5 = 0 )

    print 'fizbuz'

    else if (@i % 3 = 0)

    print 'fiz'

    else if (@i % 5 = 0)

    print 'buz'

    else

    print @i

    select @i += 1

    end

    Wouldn't this be faster?

    Yes.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Jeff Moden (2/22/2010)


    Loner (2/22/2010)


    Jeff

    Why don't you post your 'perfect' answer?

    I can tell you why... people would simply memorize instead of taking the time to figure it out. 😉

    Well, I'll post mine because it is (of course) not perfect. But I think it's fairly good.

    It's in the form of a stored procedutre that works on any number, rather than hard coded 100.

    USE play -- my sandbox db

    go

    CREATE proc FIZZBUZZ (@limit int)

    -- with RECOMPILE

    -- recompile probably not needed unless called with low numbers like 0,1 as well as big numbers

    as

    -- proc to generate FIZZBUZZ results for numbers up to about 2 billion

    if @limit < 0 return -- can't handle negative number of rows

    DECLARE @cubelim int set @cubelim = 1+POWER(@limit,1.0/3.0);

    -- rough number of rows needed in each componenet of a 3-way self-cross-join to achieve @limit in the result

    with some_columns as -- as much of master.sys.allcolumns as we need, no more

    (SELECT top (@cubelim) * from Master.sys.all_columns),

    CteNums (J) as -- create Tally cte

    (SELECT top (@limit) ROW_NUMBER() OVER (ORDER BY AC1.Object_ID) AS J

    from some_columns AC1

    CROSS JOIN some_columns AC2

    CROSS JOIN some_columns AC3)

    SELECT

    -- J as number, /* the number being tested for dividability by 3 and/or by 5 */

    -- uncomment the line above if J is wanted in the result set

    CASE when (J%15 = 0) then 'FIZZBUZZ' -- multiple of 3 and of 5

    when (J%5 = 0) then 'BUZZ'

    when (J%3 = 0) then 'FIZZ'

    else ltrim(str(J))

    END as Number_or_Name

    from cteNums

    go

    Tom

  • Steve Cullen (2/22/2010)


    Wouldn't this be faster?

    Want to test with 10mm rows and let us know?

  • Steve Jones - Editor (2/22/2010)


    Steve Cullen (2/22/2010)


    Wouldn't this be faster?

    Want to test with 10mm rows and let us know?

    Too lazy 😛

    Converting oxygen into carbon dioxide, since 1955.
  • So many fails...fizbuz? BizzBuzz?

    No attention to the specification...don't worry gents, I'll hold the door for you 😛

    Gaz

    -- Stop your grinnin' and drop your linen...they're everywhere!!!

  • GSquared (2/22/2010)


    Just to annoy Jeff, here's my "ultimate version":

    SET NOCOUNT ON;

    DECLARE @Table1 TABLE (

    ID int IDENTITY PRIMARY KEY,

    Number int);

    DECLARE @Number INT;

    SELECT @Number = 1;

    WHILE @Number <= 100

    BEGIN

    INSERT INTO @Table1 (Number)

    SELECT @Number

    WHERE @Number NOT IN

    (SELECT Number

    FROM @Table1);

    SELECT @Number = @Number + 1;

    END;

    DECLARE curNumbers CURSOR GLOBAL DYNAMIC FOR

    SELECT DISTINCT Number

    FROM @Table1

    ORDER BY Number;

    DECLARE @Number2 INT, @Number2String VARCHAR(max), @Msg VARCHAR(MAX);

    OPEN curNumbers;

    FETCH FIRST FROM curNumbers

    INTO @Number2;

    WHILE @@fetch_status = 0

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(3 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(5 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Msg = CAST(@Number2 AS VARCHAR(MAX));

    END;

    ELSE

    BEGIN

    SELECT @Msg = 'Buzz'

    END;

    END;

    ELSE

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(5 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Msg = 'Bizz';

    END;

    ELSE

    BEGIN

    SELECT @Msg = 'BizzBuzz';

    END;

    END;

    PRINT @Msg;

    FETCH NEXT FROM curNumbers

    INTO @Number2;

    END;

    CLOSE curNumbers;

    DEALLOCATE curNumbers;

    Geez Gus. Feeling like an instigator today?

    Let me guess - this took you 5m02sec to write?

    Jason...AKA CirqueDeSQLeil
    _______________________________________________
    I have given a name to my pain...MCM SQL Server, MVP
    SQL RNNR
    Posting Performance Based Questions - Gail Shaw[/url]
    Learn Extended Events

  • It boggles my mind to see how far I have to go to be competent in T-SQL. I read these columns for enlightenment but so much of it is so much higher that most things go over my head without a lot of research.

    The one point I want to make, and I have seen it here, is that the person being tested is so far above the interviewer in skill that the interviewer and other current staff can't even understand the code. We had an employee who transferred into our group who wrote code so tight that DBAs complained that it was over their heads. They said that it could not be supported because they did not understand it. Granted it could have been documented better but this person thought that it was so obvious that documentation was redundant. They (and I am not one, I'm a lowly applications analyst/programmer using T-SQL and Crystal Reports exclusively) do not subscribe or browse these columns to advance their knowledge.

  • CirquedeSQLeil (2/22/2010)


    GSquared (2/22/2010)


    Just to annoy Jeff, here's my "ultimate version":

    SET NOCOUNT ON;

    DECLARE @Table1 TABLE (

    ID int IDENTITY PRIMARY KEY,

    Number int);

    DECLARE @Number INT;

    SELECT @Number = 1;

    WHILE @Number <= 100

    BEGIN

    INSERT INTO @Table1 (Number)

    SELECT @Number

    WHERE @Number NOT IN

    (SELECT Number

    FROM @Table1);

    SELECT @Number = @Number + 1;

    END;

    DECLARE curNumbers CURSOR GLOBAL DYNAMIC FOR

    SELECT DISTINCT Number

    FROM @Table1

    ORDER BY Number;

    DECLARE @Number2 INT, @Number2String VARCHAR(max), @Msg VARCHAR(MAX);

    OPEN curNumbers;

    FETCH FIRST FROM curNumbers

    INTO @Number2;

    WHILE @@fetch_status = 0

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(3 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(5 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Msg = CAST(@Number2 AS VARCHAR(MAX));

    END;

    ELSE

    BEGIN

    SELECT @Msg = 'Buzz'

    END;

    END;

    ELSE

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(5 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Msg = 'Bizz';

    END;

    ELSE

    BEGIN

    SELECT @Msg = 'BizzBuzz';

    END;

    END;

    PRINT @Msg;

    FETCH NEXT FROM curNumbers

    INTO @Number2;

    END;

    CLOSE curNumbers;

    DEALLOCATE curNumbers;

    Geez Gus. Feeling like an instigator today?

    Let me guess - this took you 5m02sec to write?

    That sound you just heard was Jeff exploding 😀

    Converting oxygen into carbon dioxide, since 1955.
  • dennis.oconnor (2/22/2010)


    It boggles my mind to see how far I have to go to be competent in T-SQL. I read these columns for enlightenment but so much of it is so much higher that most things go over my head without a lot of research.

    The one point I want to make, and I have seen it here, is that the person being tested is so far above the interviewer in skill that the interviewer and other current staff can't even understand the code. We had an employee who transferred into our group who wrote code so tight that DBAs complained that it was over their heads. They said that it could not be supported because they did not understand it. Granted it could have been documented better but this person thought that it was so obvious that documentation was redundant. They (and I am not one, I'm a lowly applications analyst/programmer using T-SQL and Crystal Reports exclusively) do not subscribe or browse these columns to advance their knowledge.

    The fact that you come here is testament to your bright future. We all had to start somewhere (except Jeff who clearly was delivered into this world this way).

    Gaz

    -- Stop your grinnin' and drop your linen...they're everywhere!!!

  • GSquared (2/22/2010)


    Just to annoy Jeff, here's my "ultimate version":

    SOM! :w00t:

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • Here's the thing that gets me:

    Why is everyone using CASE WHEN (number % 5)=0 And (number % 3)=0, instead of CASE WHEN (number %15) = 0?

    I want to see that you've thought about the problem, not just mimicked the specification.

    --

    JimFive

  • Gary Varga (2/22/2010)


    dennis.oconnor (2/22/2010)


    It boggles my mind to see how far I have to go to be competent in T-SQL. I read these columns for enlightenment but so much of it is so much higher that most things go over my head without a lot of research.

    The one point I want to make, and I have seen it here, is that the person being tested is so far above the interviewer in skill that the interviewer and other current staff can't even understand the code. We had an employee who transferred into our group who wrote code so tight that DBAs complained that it was over their heads. They said that it could not be supported because they did not understand it. Granted it could have been documented better but this person thought that it was so obvious that documentation was redundant. They (and I am not one, I'm a lowly applications analyst/programmer using T-SQL and Crystal Reports exclusively) do not subscribe or browse these columns to advance their knowledge.

    The fact that you come here is testament to your bright future. We all had to start somewhere (except Jeff who clearly was delivered into this world this way).

    Jeff is a set-based organism who sprang into multi-being at one instant. He is the Chosen One. Morpheus has said so.

    ---------------------------------------------------------
    How best to post your question[/url]
    How to post performance problems[/url]
    Tally Table:What it is and how it replaces a loop[/url]

    "stewsterl 80804 (10/16/2009)I guess when you stop and try to understand the solution provided you not only learn, but save yourself some headaches when you need to make any slight changes."

  • CirquedeSQLeil (2/22/2010)


    GSquared (2/22/2010)


    Just to annoy Jeff, here's my "ultimate version":

    SET NOCOUNT ON;

    DECLARE @Table1 TABLE (

    ID int IDENTITY PRIMARY KEY,

    Number int);

    DECLARE @Number INT;

    SELECT @Number = 1;

    WHILE @Number <= 100

    BEGIN

    INSERT INTO @Table1 (Number)

    SELECT @Number

    WHERE @Number NOT IN

    (SELECT Number

    FROM @Table1);

    SELECT @Number = @Number + 1;

    END;

    DECLARE curNumbers CURSOR GLOBAL DYNAMIC FOR

    SELECT DISTINCT Number

    FROM @Table1

    ORDER BY Number;

    DECLARE @Number2 INT, @Number2String VARCHAR(max), @Msg VARCHAR(MAX);

    OPEN curNumbers;

    FETCH FIRST FROM curNumbers

    INTO @Number2;

    WHILE @@fetch_status = 0

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(3 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(5 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Msg = CAST(@Number2 AS VARCHAR(MAX));

    END;

    ELSE

    BEGIN

    SELECT @Msg = 'Buzz'

    END;

    END;

    ELSE

    BEGIN

    SELECT @Number2String = CAST(@Number2 AS DECIMAL(6,3))/CAST(5 AS DECIMAL(6,3));

    WHILE @Number2String LIKE '%.%'

    BEGIN

    SELECT @Number2String = RIGHT(@Number2String, LEN(@Number2String)-1)

    END;

    IF CAST(@Number2String AS BIGINT) > 0

    BEGIN

    SELECT @Msg = 'Bizz';

    END;

    ELSE

    BEGIN

    SELECT @Msg = 'BizzBuzz';

    END;

    END;

    PRINT @Msg;

    FETCH NEXT FROM curNumbers

    INTO @Number2;

    END;

    CLOSE curNumbers;

    DEALLOCATE curNumbers;

    Geez Gus. Feeling like an instigator today?

    Let me guess - this took you 5m02sec to write?

    Not sure how long it took to write. I had to look up how to declare a global cursor, since I've never bothered with one before. (Is it a good thing that I don't have the process for declaring cursors memorized?)

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • OK then let my chuck in my fifty cents.

    I haven't had time to read all comments, so I don't know if a similar solution has yet been provided. I really would like some feedback, though, as to wether or not I am in the ball park.

    I must admit that my first attempt was a while loop with an if...else, which took me about 3 minutes to rattle off. But after reading some of the comments about loops and going back to look at the execution plan I decided to put a bit more effort into this.

    It did take me a fair bit longer than 10 minutes, but I think the result is a good one. At first I was working with number tables (as suggested by Jeff Moden) and trying master.dbo.spt_values (limited to a value of 2048).

    The solution dawned on me while I was trying to populate a table variable like this:

    insert into @table

    select top 10000 ROW_NUMBER() over (order by sc1.name)

    fromsys.columns sc1,

    sys.columns sc2

    I wanted to use the table variable in a second select with the case evaluation. And then I thought there has to be a way of doing this without any DDL or table variables etc...

    I figured that ROW_NUMBER is the way to go and after a few minutes, this is what I came up with:

    select top 100

    case

    when cast(ROW_NUMBER() over (order by sc1.name) as int)%3 = 0

    and cast(ROW_NUMBER() over (order by sc1.name) as int)%5 = 0 then 'FizzBuzz'

    when cast(ROW_NUMBER() over (order by sc1.name) as int)%3 = 0 then 'Fizz'

    when cast(ROW_NUMBER() over (order by sc1.name) as int)%5 = 0 then 'Buzz'

    else cast(ROW_NUMBER() over (order by sc1.name) as varchar(8))

    end

    fromsys.columns sc1,

    sys.columns sc2

    Easily scaleable and, as far as I'm concerned, easily readable.

    Wheter or not I would have come up with this in an interview, who knows?

    I think the important point is that it was a process that started with a loop went on to a temp tally table, then a variable tally table (which was faster) and culminated in the final solution. So I think the lesson learned for me, is that I need to put a bit more effort into the way I approach problem solving and I need to get my head around the whole concept of set based thinking.

    Some feedback on this would be appreciated.

    Thanks

    Sean

Viewing 15 posts - 61 through 75 (of 363 total)

You must be logged in to reply to this topic. Login to reply