Category: Blog

  • Better Security with dbatools

    I really like the dbatools project. This is a series of PowerShell cmdlets that are built by the community and incredibly useful for migrations between SQL Servers, but also for various administrative actions. I have a short series on these items.

    One of the things that I see many junior SQL Server people struggle with (or forget) is the need to get logins onto multiple servers. This is often in situations where some sort of DR or HA technology is being used between instances. An admin will set up a second server, add logins, and forget about the entire system.

    Until something fails. Then their failover works perfectly, or mostly, or good enough, and they move on with their day. A few days later

    The cmdlet, Sync-DbaSqlLoginPermissions, is designed to help solve this issue. I certainly could use this to quickly sync logins (SQL or Windows) between two instances, but it’s great for an automated, regular sync between two HA or DR instances. If you set this up as a job, it won’t necessarily catch every login if servers fail between the syncs and a login is added, but this will give you some added protection over a long term as you make changes on one system.

    This is a way to solve some cross instance issues that are hard in T-SQL, but simple in PoSh. Kudos to the dbatools team for this cmdlet.

  • Advent of Code 2017 Day 5–#SQLNewBlogger

    Another post for me that is simple and hopefully serves as an example for people trying to get blogging as #SQLNewBloggers.

    This is day 5 of the Advent of Code 2017. If you want to read about the puzzles, start with Day 1. This is going to be a crazy looping item, since it will move through the list, relative to the current spot, and incrementing items, I know this won’t be good in SQL.

    Still. Worth solving.

    Let’s load the data. I’ll use a table, but first, I’ll also add an identity. This will help me number instructions and figure out what the next one is.

    CREATE TABLE Day5
    ( InstructionKey INT IDENTITY(1,1)
    , Instruction INT)
    GO

    There are issues with identities, but this is a great trick:

    CREATE VIEW Day5V
    AS
    SELECT d.Instruction FROM dbo.Day5 AS d
    GO
    -- reusable code
    BULK INSERT Day5V FROM 'e:\Documents\GitHub\AdventofCode\2017\Day5\Input.txt' WITH (ROWTERMINATOR='\n')
    GO

    Now I can get to work. Here’s the logic I used.

    I wanted to first set some starting points. I have a counter (0 based, increment first). This determines how many times I jump around. I also need to track the current instruction key and the next key. And, of course, I need the instruction value.

    The identity is the array index, or the instruction key (which place am I in). In this case, I’ll try to follow this logic.

    Get the end (out of bounds, which is the max + 1). I loop until I get an jump outside of the end range. The loop does these items:

    • Get the current instruction jump
    • Set the next location to be the current key + the current jump
    • Update the current jump to increment by 1
    • Set the current instruction key to the next key
    • loop

    This seems to be what I need. On the test set, this worked fine. When I first set this up, I used this code:

    DECLARE @end INT ,
             @CurrentInstructionKey INT = 1 ,
             @Instruction INT ,
             @NextInstructionKey INT ,
             @counter INT = 0;
    SELECT @end = MAX(InstructionKey) + 1
    FROM dbo.Day5 AS d;
    
    -- SELECT [end] = @end;
    
    WHILE @CurrentInstructionKey < @end
    BEGIN
         SET @counter = @counter + 1;
         SELECT @Instruction = Instruction
         FROM Day5
         WHERE InstructionKey = @CurrentInstructionKey;
         SELECT @NextInstructionKey = @CurrentInstructionKey + @Instruction;
         UPDATE dbo.Day5
         SET Instruction = Instruction + 1
         WHERE InstructionKey = @CurrentInstructionKey;
         SET @CurrentInstructionKey = @NextInstructionKey;
    --PRINT @CurrentInstruction
    END;
    
    SELECT Counter = @counter ,
            [current] = @CurrentInstruction;

    When I ran this, it chugged for some time. I bet in Python or C#, which would solve quickly with arrays. With updates, it’s slow. Like minutes slow for 1074 rows.

    However, it worked.

    Part II

    In this part, this instructions are almost the same, but based on the current instruction value, we either increase or decrease the value. Not a big change. Our new update looks like:

    UPDATE dbo.Day5
    SET Instruction = Instruction + CASE
                                         WHEN @Instruction >= 3 THEN
                                             -1
                                         ELSE
                                             1
                                     END
    WHERE InstructionKey = @CurrentInstructionKey;

    This also works, albeit slowly. I left this around 5:30 and went to the gym.

    One of the easier puzzles.

  • tSQLt tests for Day 5 Advent of Code 2017

    This is day 5 of the Advent of Code 2017. If you want to read about the puzzles, start with Day 1.

    As I worked through the puzzles, I decided that I should be testing using their test sets and solving the issues that way. This lets me use the sample data, but also add in my own sets to cover strange situations.

    Here are the tests that I used for each part.

    Part I

    For part 1, only a short test is needed. Since we’re looking for a scalar value, I could easily just added an INT variable for the actual and expected values. I set this to the value given in the problem.

    Then I fake the table and insert the test set. From here, I can call my proc that implements the algorithm and get the result value.

    EXEC tsqlt.NewTestClass @ClassName = N'tDay5';
     GO
     CREATE OR ALTER PROCEDURE tDay5.[test day5 a initial set]
     AS
     BEGIN
    
    -- Assemble
     DECLARE @actual INT = 0, @expected INT = 5;
    
    EXEC tsqlt.FakeTable @TableName = N'Day5' , @Identity = 1
     INSERT Day5
     VALUES
     (0 ), (3), (0), (1), (-3);
    
    -- Act
     EXEC @actual = SolveDay5a;
    
    -- Assert
     EXEC tsqlt.AssertEquals @Expected = @expected, @Actual = @actual, @Message = N'Failed to account'
    
    END

    Part II

    The test is the same, just calling a different procedure that implements the part II algorithm.

    CREATE OR ALTER PROCEDURE tDay5.[test day5 initial set]
     AS
     BEGIN
    
    -- Assemble
     DECLARE @actual INT = 0, @expected INT = 10;
    
    EXEC tsqlt.FakeTable @TableName = N'Day5' , @Identity = 1
     INSERT Day5
     VALUES
     (0 ), (3), (0), (1), (-3);
    
    -- Act
     EXEC @actual = SolveDay5b;
    
    -- Assert
     EXEC tsqlt.AssertEquals @Expected = @expected, @Actual = @actual, @Message = N'Failed to account'
    
    END
  • SQL in the City is coming Feb 28

    The next edition of the SQL in the City broadcast is coming Feb 28, and I’m planning travel now to head back to the UK for the event. The schedule is up on the Redgate Hub Livestream page.

    This edition has lots more GDPR/security/masking content as well as updates on the new products.

    Mark the date on your calendar, let your boss know it’s a training day, and get some friends together to join us for the day.