Category: Blog

  • A Practical Approach to Version Control

    Abstract

    Chances are, your team has several point-in-time backups for your databases. After all, they’re essential for recovering the system in an emergency. And, chances are, you’ve got a version control system (VCS) to provide the same capabilities for your applications.

    But what about version control for the database, too?

    Come to this session to see how you can create a more efficient database development platform by integrating your VCS with SQL Server. In real-time, you’ll see how versioning, branching, merging, and the other manual tasks you hate can fade away with just a few tips, tricks, and tools.

    Level: 200

    Demos

    I’ve built these demos:

    • Connecting your database to a version control system. I use Git here, but can use SVN (or TFS online with connectivity)
    • History and Changes – Getting a few of the changes made over time, tracking to a user, undoing changes.
    • Object Locking – Using Redgate’s SQL Source Control, but explaining how a semaphore is needed
    • Branching – A look at creating a branch in Git and then working with a second database.

    Downloads

    Powerpoint: SITC15_SteveJonesPracticalVCS.pptx

  • Playing with Themes

    I’m not much of a designer. Indeed, I’m best at just putting up tables and information, not producing visualizations. However I wanted to make the blog look a little better (and SSC, for that matter). As a result, I’ve carved out a few minutes here and there to play with themes for this blog. I haven’t often found one that I liked, but ran across one today that I thought I’d try.

    I’ll see how this looks for now. I don’t love that all my sidebar stuff moved to the bottom, but that’s a cleaner look for sure. I may play around with this a bit, and comments are certainly welcome. I’d like to use a few more images in writing as I think they can break up the text, and certainly some of the scrolling images convey interesting thoughts. I’d like to start using some for code as well, showcasing results as wide images.

     

  • Traveling in Wales

    It’s SQL Relay Cardiff day today. This is my first time in Wales, and it’s a busy day at SQL Relay. It’s a bit of deja vu with me delivering the same session on Version Control today that I presented 18 ours ago at SQL Relay Bristol.

    It’s interesting being on part of the SQL Relay tour, with some of the same speakers, some different, the rapid travel from one city to the next, and orienting myself in a new environment. The venues are much different, with a set of hotel conference rooms yesterday and a large arena facility (the Motorpoint Arena) today.  It’s surprisingly confusing trying to find toilets, speaker rooms, and more.

    However the people are nice, and friendly, although quiet. I got lots of good questions both days, on a semi-confusing topic, and that will help me revisit the session and make some changes over the next few days.

    I get to help on a second session today as we have a speaker that’s ill. Then it’s some work as I prep for travel back to London and SQL in the City in London on Friday.

     

  • A tSQLt Mistake – Debugging a Test

    While I was working on a test the other day, it kept failing. Not a big surprise, but I couldn’t figure out why. When I looked at tsqlt.testresults, I saw extra rows. Double rows in fact, and that threw me.

    This was my Assemble code.

    -- Assemble
    CREATE TABLE #Expected (
    yearnum int
    , monthnum TINYINT
    , salestotal money
    )


    INSERT INTO #Expected
    ( yearnum
    , monthnum
    , salestotal
    )
    VALUES
    ( 2012, 11, 2500.23 )
    , ( 2012, 12, 2200.15 )
    , ( 2013, 1, 2656.75 )

    SELECT *
    INTO #actual
    FROM #Expected AS e

    EXEC tsqlt.FakeTable @TableName = N'MonthlySales', @SchemaName='dbo';

    INSERT dbo.MonthlySales
    VALUES
    ( 11, 1000.00)
    , ( 11, 1500.23)
    , ( 12, 2200.15)
    , ( 13, 1000.00)
    , ( 13, 1656.00)
    , ( 13, 0000.75);

    Here was the output (ignoring the failure messages):

    [tArticles].[test sum of sales by month for multiple months] failed: (Failure) The calculations are incorrect

    |_m_|yearnum|monthnum|salestotal|

    +—+——-+——–+———-+

    |=  |2012   |11      |2500.2300 |

    |=  |2012   |12      |2200.1500 |

    |=  |2013   |1       |2656.7500 |

    |>  |2013   |1       |2656.7500 |

    |>  |2012   |12      |2200.1500 |

    |>  |2012   |11      |2500.2300 |

     

    Hmmm. What’s going on? Why don’t the rows match? If I run the query, I see the results I expect. Is it the query or test?

    In this case, you read the results as showing that I have 3 rows that are the same in my expected and actual tables (@expected and @actual variables in the assert). However I also have 3 extra rows in the actual table, which appear to be duplicates.

    If I go back to the Assemble, I see a pattern that’s a problem. Some people might think these hassles are a way to give up on testing. Some might build a better pattern. I’ll do the latter.

    In this case I create the expected table and then I insert the expected results. Then I create my actual table from the expected one to keep the schema the same and avoid repeating code. However in this case I have a bug.

    The bug is I’m moving the expected results to actual. If I asserted at this point, I’d pass. However then I run the query and insert the results, which happen to be the same as the expected results (my query works). If the query didn’t work, I might really spend a lot of time debugging it, but here I can tell my test code is buggy.

    I have two choices to fix this.

    1. Add a WHERE clause of WHERE 1 = 0 (no rows inserted)
    2. Move the creation of the actual table.

    My first thought was to adjust the pattern to this:

    CREATE TABLE #Expected (
    yearnum int
    , monthnum TINYINT
    , salestotal money
    )

    SELECT *
    INTO #actual
    FROM #Expected AS e


    INSERT INTO #Expected
    ( yearnum
    , monthnum
    , salestotal
    )
    VALUES
    ( 2012, 11, 2500.23 )
    , ( 2012, 12, 2200.15 )
    , ( 2013, 1, 2656.75 )

    I move the #Actual and #Expected tables together, so that once I get the results set, I immediately create the #Actual copy. I could leave things and do this:

    CREATE TABLE #Expected (
    yearnum int
    , monthnum TINYINT
    , salestotal money
    )


    INSERT INTO #Expected
    ( yearnum
    , monthnum
    , salestotal
    )
    VALUES
    ( 2012, 11, 2500.23 )
    , ( 2012, 12, 2200.15 )
    , ( 2013, 1, 2656.75 )

    SELECT *
    INTO #actual
    FROM #Expected AS e
    WHERE 1 = 0

    EXEC tsqlt.FakeTable @TableName = N'MonthlySales', @SchemaName='dbo';

    Maybe the best thing is to be careful and do this:

    -- Assemble
    CREATE TABLE #Expected (
    yearnum int
    , monthnum TINYINT
    , salestotal money
    )

    SELECT *
    INTO #actual
    FROM #Expected AS e
    WHERE 1 = 0

    INSERT INTO #Expected
    ( yearnum
    , monthnum
    , salestotal
    )
    VALUES
    ( 2012, 11, 2500.23 )
    , ( 2012, 12, 2200.15 )
    , ( 2013, 1, 2656.75 )

    Combine the ideas and keep this insulated from refactoring moving or adding code in there.

    Remember, tests are code. This is why they should fail first, so that you have some confidence in your code working and causing a test to pass.