Author: way0utwest

  • SQL Prompt Gets Even Better

    SQL Prompt v9 came out recently, and just when you thought they couldn’t make it better, they found a way. If you click the menu for SQL Prompt, you’ll see a couple new items.

    2017-11-29 14_55_40-SQLQuery2.sql - (local)_SQL2016.AdventureWorks2014 (PLATO_Steve (66)) - Microsof

    Code Analysis!!! Finally, a first step towards some sort of better analysis of code. These are a set of rules from our SQL Code Guard acquisition and we’ve integrated these into Prompt. Now you’ll get some green squiggly’s to alert you to potential issues.

    For example, I get two in this short, poorly written code. The first item is a TOP without an ORDER BY, which usually isn’t a good thing.

    2017-11-29 14_59_07-SQLQuery2.sql - (local)_SQL2016.AdventureWorks2014 (PLATO_Steve (66))_ - Microso

    The second item is one of those that I would like to put in all CAPs for developers. No asterisks.

    2017-11-29 14_59_11-SQLQuery2.sql - (local)_SQL2016.AdventureWorks2014 (PLATO_Steve (66))_ - Microso

    Right now there are a set of static rules, but we are working to add more and allow you to customize these items. We’re also looking for feedback on how you might like to apply or surface these rules to your staff. Please, if you have comments or questions, ask at the Redgate Hub.

    For now, you can disable analysis, or disable selected rules. Click the Manage link, and you’ll see a list of rules, which you can turn off as needed.

    2017-11-29 14_55_51-Sql Prompt - Code analysis rules

    Static analysis of SQL code has a long way to go, but I am looking forward to seeing more improvements appear in SQL Prompt and our other products over time.

  • Testing a Birthday Month Query

    I ran across a post from a tester, wondering  how to write a query for birthday months. This makes sense, as I’m sure some businesses want to notify or track customers that have birthdays this month and give them something.

    The post was good, with DDL and test data, and ignoring the discussion about database design, how would you test htis? If you look through the test data, surely you might decide to check for Jan, or Feb, etc., but are you use as the query might change that you’re checking everything?

    This is where testing can help. I’d start with a simple test. One that uses some data and checks that nothing is returned.

    CREATE OR ALTER PROCEDURE tTSQLTests.[test birthday queries for a Jan with no birthdays in range]
    /*
    Description:
    
    Changes
    11/22/2017
    */
    AS
    BEGIN
         -------------
         -- Assemble
         -------------
         DECLARE @begin DATETIME = '1994-01-01' ,
                 @end DATETIME = '2000-01-01' ,
                 @month TINYINT = 1;
    
        EXEC tSQLt.FakeTable @TableName = 'birthdays', @SchemaName = 'dbo';
         INSERT dbo.birthdays
         (
             cust_id ,
             cust_fname ,
             cust_lname ,
             cust_dob
         )
         VALUES
         (94, N'Jamie', N'Aguiar', '2017-06-02 00:00:00.000') ,
         (346, N'Keith', N'Brady', '1993-03-29 00:00:00.000') ,
         (361, N'Kelsea', N'Britto', '1994-03-25 00:00:00.000') ,
         (715, N'Tia', N'Delguidice', '1999-02-04 00:00:00.000') ,
         (994, N'Holly', N'Hamilton', '2017-11-12 00:00:00.000') ,
         (1110, N'ISABELLE', N'HYDER', '1993-04-06 00:00:00.000') ,
         (1295, N'RAELYN', N'LITTLE', '1995-02-15 00:00:00.000') ,
         (1403, N'ALLISON', N'RIPA', '1993-10-14 00:00:00.000') ,
         (1486, N'Rayvon', N'Miller', '1984-11-09 00:00:00.000') ,
         (1559, N'Alexandra', N'Sousa', '1989-09-17 00:00:00.000') ,
         (1897, N'Patrick', N'Snow', '1976-10-10 00:00:00.000') ,
         (1749, N'Justine', N'Zienowicz', '1998-03-12 00:00:00.000'),
         (2209,N'Brittany',N'Kosboski','1987-01-22 00:00:00.000')
         ;
    
        CREATE TABLE #Expected
         (
             cust_id INTEGER NOT NULL PRIMARY KEY ,
             cust_fname NVARCHAR(50) NOT NULL ,
             cust_lname NVARCHAR(50) NOT NULL ,
             cust_dob DATETIME NOT NULL
         );
    
    
    
    
        SELECT TOP 0
             cust_id ,
             cust_fname ,
             cust_lname ,
             cust_dob
         INTO #Actual
         FROM #Expected;
    
        ---------------
         -- Act
         ---------------
         INSERT #Actual
         SELECT cust_id ,
                cust_fname ,
                cust_lname ,
                cust_dob
         FROM birthdays
         WHERE cust_dob >= @begin
               AND cust_dob < @end
               AND MONTH(cust_dob) = @month;
    
        ---------------
         -- Assert    
         ---------------
         EXEC tSQLt.AssertEqualsTable @Expected = N'#expected' ,
                                      @Actual = N'#actual' ,
                                      @Message = N'The query doesn''t work';
    
    END;
    
    
    GO
    -- GRANT EXECUTE ON tTSQLTests.[test birthday queries for a month] to userrole
    EXEC tsqlt.run 'tTSQLTests.[test birthday queries for a Jan with no birthdays in range]'

    Then I’d test for one birthday.

    CREATE OR ALTER PROCEDURE tTSQLTests.[test birthday queries for a Jan with one birthdays in range]
    /*
    Description:
    
    Changes
    11/22/2017
    */
    AS
    BEGIN
         -------------
         -- Assemble
         -------------
         DECLARE @begin DATETIME = '1984-01-01' ,
                 @end DATETIME = '2000-01-01' ,
                 @month TINYINT = 1;
    
        EXEC tSQLt.FakeTable @TableName = 'birthdays', @SchemaName = 'dbo';
         INSERT dbo.birthdays
         (
             cust_id ,
             cust_fname ,
             cust_lname ,
             cust_dob
         )
         VALUES
         (94, N'Jamie', N'Aguiar', '2017-06-02 00:00:00.000') ,
         (346, N'Keith', N'Brady', '1993-03-29 00:00:00.000') ,
         (361, N'Kelsea', N'Britto', '1994-03-25 00:00:00.000') ,
         (715, N'Tia', N'Delguidice', '1999-02-04 00:00:00.000') ,
         (994, N'Holly', N'Hamilton', '2017-11-12 00:00:00.000') ,
         (1110, N'ISABELLE', N'HYDER', '1993-04-06 00:00:00.000') ,
         (1295, N'RAELYN', N'LITTLE', '1995-02-15 00:00:00.000') ,
         (1403, N'ALLISON', N'RIPA', '1993-10-14 00:00:00.000') ,
         (1486, N'Rayvon', N'Miller', '1984-11-09 00:00:00.000') ,
         (1559, N'Alexandra', N'Sousa', '1989-09-17 00:00:00.000') ,
         (1897, N'Patrick', N'Snow', '1976-10-10 00:00:00.000') ,
         (1749, N'Justine', N'Zienowicz', '1998-03-12 00:00:00.000') ,
         (2209, N'Brittany', N'Kosboski', '1987-01-22 00:00:00.000');
    
        CREATE TABLE #Expected
         (
             cust_id INTEGER NOT NULL PRIMARY KEY ,
             cust_fname NVARCHAR(50) NOT NULL ,
             cust_lname NVARCHAR(50) NOT NULL ,
             cust_dob DATETIME NOT NULL
         );
    
        INSERT #Expected
         (
             cust_id ,
             cust_fname ,
             cust_lname ,
             cust_dob
         )
         VALUES
         (2209, N'Brittany', N'Kosboski', '1987-01-22 00:00:00.000');
    
        SELECT TOP 0
             cust_id ,
             cust_fname ,
             cust_lname ,
             cust_dob
         INTO #Actual
         FROM #Expected;
    
        ---------------
         -- Act
         ---------------
         INSERT #Actual
         SELECT cust_id ,
                cust_fname ,
                cust_lname ,
                cust_dob
         FROM birthdays
         WHERE cust_dob >= @begin
               AND cust_dob < @end
               AND MONTH(cust_dob) = @month;
    
        ---------------
         -- Assert    
         ---------------
         EXEC tSQLt.AssertEqualsTable @Expected = N'#expected' ,
                                      @Actual = N'#actual' ,
                                      @Message = N'The query doesn''t work';
    
    END;
    
    
    GO
    -- GRANT EXECUTE ON tTSQLTests.[test birthday queries for a month] to userrole
    EXEC tSQLt.Run 'tTSQLTests.[test birthday queries for a Jan with no birthdays in range]';
    EXEC tSQLt.Run 'tTSQLTests.[test birthday queries for a Jan with one birthdays in range]';

    Next, I’d add a few more tests for other cases, perhaps checking that leap years, etc. run correctly.

    Is this hard to setup? Well, I might argue that the time you spend examining result sets and checking random queries is about the same. Once I’ve written this test, which took about 10 minutes with a template, I can easily copy/paste the test, change the name and move data around. Ideally I’d stick this query in some procedure instead and run the test that way, which makes it easy for me to alter the query and re-run a ton of tests quickly.

    The time saved isn’t in the initial development, but in the checking when I touch this code again, or tune it. What if I decided to replace the MONTH() check with a computed column, as suggested by some responders? Then my tests should still pass with a new query.

    Testing builds better software. Not perfect, but better. And I can get better as developing over time by adding more tests.

  • A Christmas Bug

    It’s not really a big deal for me, despite the fact that I travel to Europe in a few days for two weeks. At least, I’m fairly confident this won’t be an issue for me. A few of my fellow #sqlfamily might not be so lucky, as they use a different airline.

    Apparently American Airlines has a bug in their scheduling system. It’s not a safety bug, don’t worry about that, but it’s potentially a huge bug for the company in terms of profit and cost. The bug is a part of the system that lets pilots request holiday time off. The system allowed too many pilots to take vacation, and as a result, American Airlines (AA) doesn’t have enough pilots to fly their planes.

    In case you wonder about the scope of this, it’s 15,000+ flights that are affected. AA flies about 6,700 flights a day and are the world’s largest airline by some measure. They are offering pilots 150% of their normal rate, which is apparently the max allowed by contract. I’m sure some pilots will take the offer, but I’m also sure there may be some flight cancellations. After all, pilots have likely made their own plans, which they may not want to change. Apparently some have as the news as of this writing is a few hundred flights.

    The complexity of airline scheduling software has to be quite high, and while this won’t really endanger lives, it will affect the profitability of AA. This is definitely a development mistake, and one that should have been caught in testing. I don’t know how often this software is updated, nor what their process is. Someone suggested this is outsourced software, but that doesn’t matter. We clearly have a software development failure here.

    I certainly think developers are responsible for testing their code and meeting requirements. This includes not assuming the happy path is followed. However, this is also a place where we need (as an industry) to learn to better test the bounds and limits of our software. We need to be sure that we account for not only security, but pushing the limits of use by legitimate users. Software mistakes cost money, and as we continue to use computing more and more, we need to become better at testing our code. Our systems are very complex these days, more complex than a single person can handle. We need better testing everywhere, including the database.

    Please, make an effort to test better next year, in both your application and database. Use larger data sets at some point (both numbers and dates), add automated testing as a part of your development routine, and assume that users will do stupid, silly, and malicious things with inputs.

    Steve Jones

    The Voice of the DBA Podcast

    Listen to the MP3 Audio ( 4.4MB) podcast or subscribe to the feed at iTunes and Libsyn.

  • Not Useless Features

    Some time ago I noticed Adam Machanic had written a post titled The SQL Hall of Shame. In it, Adam notes there are features that Microsoft will introduce in SQL Server and then let die. These are the useless features that aren’t widely used, or even useful for many projects. You can read his list, and agree or disagree.

    I think there certainly are some features that were silly experiments and I wish they had been introduced as experimental, or beta, features early, allowing users to give feedback on whether they’re useful and where they need refinement. I certainly think too many resources were initially wasted on items like MDW and Query Notifications, and far too little investment later. These days I think we’ll see more early releases of items in Azure where users can experiment and provide feedback to help Microsoft decide if more investment is needed. At least, that’s my hope.

    Today I’m wondering if you think there are features in SQL Server that do need more attention. Those features you use, but appear forgotten and you’d hope they are improved in the next version.

    For me, I certainly wish replication would get more attention, tooling, and resilience. I’m not sure if this needs an overhaul, like SQL Server 2005 was, or there just needs to be some reworking of the code, but in today’s distributed world, we need a more reliable way to hook up portions of databases and move data around. Not ETL, not Availabilty Groups, a better replication architecture and implementation.

    There might be other features you use or want, but let me know today. What’s a not useless feature that you want improved.

    Steve Jones

    The Voice of the DBA Podcast

    Listen to the MP3 Audio ( 2.8MB) podcast or subscribe to the feed at iTunes and Libsyn.