FizzBuzz

  • Jeff Moden (2/22/2010)


    ... which one do you think I'll pick?

    The one that says pork chop the most :w00t:

  • OK Jeff, I did the original problem in about 4 minutes. I thought it was good, but then I read the first 1/3 of your article. I have started the problem over and in about 2 minutes I put your solution into play. For a million records mine was 1:30 your way of thinking is about 10 seconds. and half the code.

    Where I work we send an assignment home with the applicants that make it through the first interview and we give them two weeks. We tell them we do not want to see it for two weeks and see what they come back with. We check to see if they have a workable solution first, but then we check the level of the code and see if they tried or just made it work. We have gotten much better programmers this way, because they are not rushed.

    John

    [font="Tahoma"]John Burris:hehe:
    MCITP Database Administrator[/font]

  • J.Faehrmann (2/22/2010)


    No offence taken, Jeff. But you made me think about my habits, thanks for that 🙂

    Being lazy and pragmatic is a very important developer attitude to me.

    I never realized that it could look that bad in an interview if the competition was just a bit less lazy.

    Now THAT's the spirit, JF! Glad someone gets what I'm trying to say and I do appreciate the feedback.

    As a side bar, consider the people that actually are taking offense to what I'm saying here... that attitude will come out in the post-test interview (where we talk about the code they've written) and guess which ones won't fall into the "right fit" category? 🙂 The wrong attitude will definitely show and the interviewer will definitely pick up on it.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • John Burris (2/22/2010)


    OK Jeff, I did the original problem in about 4 minutes. I thought it was good, but then I read the first 1/3 of your article. I have started the problem over and in about 2 minutes I put your solution into play. For a million records mine was 1:30 your way of thinking is about 10 seconds. and half the code.

    Where I work we send an assignment home with the applicants that make it through the first interview and we give them two weeks. We tell them we do not want to see it for two weeks and see what they come back with. We check to see if they have a workable solution first, but then we check the level of the code and see if they tried or just made it work. We have gotten much better programmers this way, because they are not rushed.

    John

    Now we're talking! Another person "gets it". I also very much like your weeding "tool"... give them all the time to put their absolute best foot forward. No excuses... just quality code. And thanks for stepping up with the feedback. Hopefully folks will take your feedback and run like hell with it. I also very much appreciate the fact that you DIDN'T post your answer... people need to learn, not just memorize. Very well done, John!

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

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


    Jeff Moden (2/22/2010)


    ... which one do you think I'll pick?

    The one that says pork chop the most :w00t:

    Heh... nope... the one that brings in the BBQ pack gets extra points! 😛

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

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


    All things being equal, you pick the guy with the set based solution. However I've rarely seen "all things equal" between two candidates in an interview. The better the solution (and quicker), the better you'd score in an interview.

    The point of the editorial, and this test, however, is to remove those candidates that can't clear a bar.

    Again, I agree... it's a good weeding tool. But the smart candidate will turn it into "the winning entry".

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • 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;

    - 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

  • 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;

    ...well that last candidate wasted my time!!!

    Gaz

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

  • Jeff Moden (2/21/2010)


    Heh... I just Googled "FIZZBUZZ SOLUTIONS SQL"... I'm amazed and surprised that some of those folks had the nerve to publish some of the solutions they have. Maybe it's a good test after all.

    First I tried writing a set-based solution which had to generate its numbers table (so that it would scale beyond my pre-existing tally table) and the I tried writing a loop-based one, just to see which I could write quicker. They both took about the same time to write. I must have been reading too much of your stuff Geoff, because I am not really an SQL programmer!

    Then, seeing your comment, I googled it too - just to see what was out there. The first one that came up had me laughing myself silly: some poor lad had produced a poor solution (using a recursive CTE to generate the numbers table) and was advised by an "expert" to change it to an appalling solution (using the number column of master.dbo.spt_values, which is totally unscalable beyond 2048). The next thing I found was someone asking for advice on what would be a decent T-SQL equivalent of FizzBuzz; the answers were pretty varied, and didn't include what is, in my opinion, the obvious one: use FIZZBUZZ with one miniscule change: instead of 100 write 10000000 - anyone who writes a loop for that is a waste of space! I decided that I'd had enough amusement and didn't look at any more of the search results.

    Of course the best way of making FIZZBUZZ into a genuine T_SQL test is to ask someone to write a stored procedure that takes the limiting number as a parameter - so they have to cope with whatever number is passed in. That eliminates the use of a pre-generated Tally table (otherwise of course for 100 (indeed, up to 11000) I could just use my permanent Tally table).

    By the way, there was method in choosing a hundred million as a limit - it's big enough to need a 3-way cross join of master.sys.all_columns to generate the CTE, and small enough that limiting the size of that cross join (by not cross-joining the whole table to itself, but joining part of the table to itself) is useful.

    Tom

  • Gary Varga (2/22/2010)


    ...well that last candidate wasted my time!!!

    C'mon, I'm sure you'd end the interview after

    DECLARE curNumbers CURSOR

    How long could that take?

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


    Gary Varga (2/22/2010)


    ...well that last candidate wasted my time!!!

    C'mon, I'm sure you'd end the interview after

    DECLARE curNumbers CURSOR

    How long could that take?

    Steve,

    I must have posted here too often. I agree with what I am certain you are implying - yep, the use of cursors - however, anyone who thinks that curNumbers is a valid name will have the door open for them due to the risk that they are unable to use a handle themselves.

    I make no apologies G-Squared. Naming in Software Engineering is more important than most, if not everything, so far mentioned in this thread.

    Jeff may get on his soapbox once in a while but I for one applaud him for it.

    Gaz

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

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

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

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


    Gary Varga (2/22/2010)


    ...well that last candidate wasted my time!!!

    C'mon, I'm sure you'd end the interview after

    DECLARE curNumbers CURSOR

    How long could that take?

    Steve! C'mon! It shouldn't even get that far!

    Declaring the table variable should be as far as that one goes. Not because it's a table variable, but because it's got a surrogate key that should actually have the value you want for the row! Just change the first column so it doesn't have an identity property, and get rid of the second column completely.

    Then it populates it with a while loop that includes a "where not in" that's completely unnecessary! We're talking serious performance hits there on anything with enough rows to matter. Add that it's on a non-indexed column in a table variable, and we're looking at a Nested Loops operation on a table scan.

    Both of those are before declaring the cursor. Shouldn't even get that far before spewing soda all over the screen in shock! 🙂

    This was meant to be a masterpiece of garbage T-SQL. The fact that it's got a cursor in it is a minor detail.

    - 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

  • You are correct, the declare table should stop things. I might be curious to see where someone was going, but the declare cursor would drop someone way down my list immediately.

    For the record, I think Jeff is correct. You write the best code you can, and for a DBA that means set-based. The two things I'd think of write away are the WHILE loop, and the recursive CTE, which I know isn't any better, and IMHO, is harder to read. I can't compete with Jeff on the set based one, and in an interview I'd be aiming for points by a) solving the issue and b) solving it quickly.

    I still think I'd beat Jeff with a winning smile, a Friday shirt, and an extra Starbucks card I could leave on the table 😀

  • 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?

    Converting oxygen into carbon dioxide, since 1955.

Viewing 15 posts - 46 through 60 (of 363 total)

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