Category: Blog

  • Learning from Mistakes: T-SQL Tuesday #194

    We’re a week late, once again my fault. I was still coming out of the holidays and forgot to check on my host. Luckily, Louis Davidson (who did have Feb) agreed to go early. He has a nice invite, and I am glad to answer.

    This is the monthly blog party on something SQL Server/T-SQL/etc. related. I have about half of 2026 covered, but if you would like to host, I’d love to have you. Ping me on X/LinkedIn/BlueSky.

    A Mistake

    Since we aim for T-SQL, I decided to ping something I’ve done a number of times in T-SQL, and sometimes still break. However, a little testing has helped me (mostly) keep this from getting to production.

    Always have testing in place.

    I am good at T-SQL, but not amazing.  I learn things from others all the time, and these days, take help from AIs, though I do test and double check what they do.

    One of the places I’ve struggled with is with outer joins. Usually left/right outer joins where I am trying to get a list of things from a join, but filter out some of the missing items. Here’s an example from Northwind. I want a list of customers joined to orders, but I might have a way where customers filter out those who haven’t been charged freight. There’s likely some business reason, but it escapes me now.

    If I run this query, I get lots of stuff.

    2026-01_0109

    That doesn’t seem right. If I check, I see this:

    2026-01_0111

    What’s the problem here? Well, the main issue is one I keep doing, fortunately, I catch this. If I move the Freight IS NULL to  WHERE instead of the ON, it works. You can see this below.

    2026-01_0112

    If I see too much data, which can be hard to catch in large result sets, I can ask Prompt AI.

    2026-01_0113

    I get the response I’d expect from most AIs.

    2026-01_0114

    How do I test for this? Well, the best way is to have test coverage for queries. For example, I might build a test like this:

    EXEC tsqlt.NewTestClass @ClassName = N’QueryTests’ — nvarchar(max)
    go

    CREATE OR ALTER PROCEDURE [QueryTests].[TestCustomersWithoutOrders]
    AS
    BEGIN
    — Arrange
    — Create temporary table to hold expected results
    DECLARE @Expected TABLE
    (
    CustomerID nchar(5)
    )

    — Insert the expected result – customers with no orders
    INSERT INTO @Expected
    SELECT CustomerID
    FROM dbo.Customers
    WHERE CustomerID NOT IN
    (
    SELECT DISTINCT CustomerID FROM dbo.Orders WHERE CustomerID IS NOT NULL
    )

    — Act
    — Create temporary table to hold actual results
    DECLARE @Actual TABLE
    (
    CustomerID nchar(5)
    )

    — This should be the query that’s being tested
    INSERT INTO @Actual
    SELECT DISTINCT
    Customers.CustomerID
    FROM dbo.Customers
    LEFT OUTER JOIN dbo.Orders
    ON Orders.CustomerID = Customers.CustomerID
    WHERE Orders.CustomerID IS NULL

    — Assert
    — Check that we have exactly 2 results
    DECLARE @ActualCount INT =
    (
    SELECT COUNT(*)FROM @Actual
    )

    IF @ActualCount <> 2
    BEGIN
    EXEC tSQLt.Fail ‘Expected exactly 2 customers without orders, but got ‘,
    @ActualCount;
    RETURN;
    END

    — Check that we got the expected customers
    IF EXISTS
    (
    SELECT 1
    FROM @Expected e
    WHERE NOT EXISTS
    (
    SELECT 1
    FROM @Actual a
    WHERE a.CustomerID = e.CustomerID
    )
    )
    OR EXISTS
    (
    SELECT 1
    FROM @Actual a
    WHERE NOT EXISTS
    (
    SELECT 1
    FROM @Expected e
    WHERE e.CustomerID = a.CustomerID
    )
    )
    BEGIN
    EXEC tSQLt.Fail ‘The actual set of customers without orders does not match the expected set.’;
    END
    END;

    That’s a lot of code, but I can see it works. I get two customers back, which is what I expect. Lines 53-58 have my query being tested above. If I run the test, it passes.

    2026-01_0115

    If I change those lines to put the filter in the ON clause (and remove WHERE), it fails.

    2026-01_0116

    Ideally I’d have this in a proc so I can change/tune this and compare plans, run tests easily, etc.

    This is a mistake I still make at times today, albeit rarely. Now I write some tests to look for my mistake. Maybe that’s the thing I’ve learned the most: have tests for my code.

  • Stupid Things I Did With AI: ASCII Art

    I ran across this article recently (https://www.gatesnotes.com/meet-bill/source-code/reader/microsoft-original-source-code) and it has a great opening piece of ASCII Art. I have a screenshot here:

    2026-01_0243

    For some reason, I thought, “I should do this in SQL”.” Then I thought, can the AIs help?

    Let’s see.

    This is part of a series of experiments with AI systems.

    SQL Prompt AI

    My first instinct is to use Claude first, but here I decided to ask SQL Prompt AI for help. I generically asked for a function that would take a word as a parameter and then produce ASCII Art. I ended up with a function and a procedure. I won’t show all the code, but I ended up with this result.

    2026-01_0238

    I thought this might be cutting off the message, but “Hello” produced “Helo”. So I asked SQL Prompt AI to alter the function to fix this. It tried, but it put a CTE in a subquery, which isn’t valid.

    2026-01_0241

    I pasted in the error message, but it returned me advice, not new code.

    2026-01_0239

    I suspected this might be because I had a few batches in this query window, so I copied just the function to another window, then pasted in the error and things got fixed.

    2026-01_0242

    Claude

    While SQL Prompt was working, I opened a tab for Claude and asked a question: I want a generic MSSQL function that returns ascii art for a character passed in

    I got the results, which were good, but only for one letter. Good, but I realized I had done a poor job of specifying my intention.

    2026-01_0244

    I then added another prompt to this chat: can I get a wrapper here that let’s me pass in a word and get the word returned as one result set?

    This returned me a wrapper function with an explanation. The code is in my repo (linked below).

    2026-01_0245

    When I tested this a bit, it worked well, including with spaces.

    2026-01_0237

    Summary

    I added this to my AIExperiments repo under the ASCII Art folder. You can check out the code and play if you want, or ask your own AI to do this.

    This is a big waste of LLM compute, and really SQL Server core compute, but it’s fun. It was something I could have written, but how tedious is it to produce a function to do this? Even if I were to try and write an algorithm to produce letters from art, I could, but it’s not really worth the effort other than as an exercise to solve the problem.

    This is also something I would guess many programming students work through. I haven’t had this, but I had to shuffle a deck of cards and other types of simulation exercises to help me learn to think in algorithms.

    I do think working through algorithms is a good use of your time. It helps you think and learn and doing this will absolutely help you better judge the quality of other code, including that written by AIs.

    However, I have done some of this work, and it’s not a good use of my time. Or likely the LLMs, but it was fun. I’ll likely use this in some Question of the Days in the future somehow.

  • Simple Talks Podcasting in 2026

    I’m in the UK today, having arrived this morning in London. Hopefully, by this time ,I’m in Cambridge and at the Redgate office. Maybe sitting in the foyer alcove, playing a little guitar (like I did last Oct).

    2026-01_0149

    I’m here for a week of Redgate meetings as we kick off the year and it’s good to see colleagues and friends. All of the advocates are here, including Pat Wright, our newest advocate, and we’re hoping to record a Simple Talks podcast episode this afternoon. Maybe a second one if I can get someone from our data team to come in on a Monday.

    Part of this week will be some brainstorming and planning for the year and I’m wondering if there are things you’d like us four advocates (myself, Grant, Kellyn, and Pat) to cover and discuss. Any hot database topics or things you’d want to hear about?

    Leave a comment for me if there are things you want to discuss. Otherwise, we’ll have to come up with things that we think might be of interest to you out there.

  • Flyway Tips: AI Generating Migration Script Names

    AI is a big deal in 2026, and at Redgate, we’re experimenting with how AI can help developers and DBAs become better at their jobs. One of the areas we’ve started to add some AI is in Flyway Desktop (FWD), with a few features designed to help reduce the cognitive load and context switches needed while developing code, and help users better understand what changes they’re making in their systems.

    I wrote about summaries of migrations scripts last week, which are helpful when you or your colleagues don’t generate good script names, or commit messages. This post looks at another of those changes, which is the generation of the script name.

    I’ve been working with Flyway and Flyway Desktop for work more and more as we transition from older SSMS plugins to the standalone tool. This series looks at some tips I’ve gotten along the way.

    Generating Complex Scripts

    In Flyway, we call the deployment scripts “migration scripts”, but they are the same thing. These are scripts that are changing, altering, or evolving our database schema in some way. New or altered objects, various schema items, and more.

    Our guidance for a lot of customers is to keep the migration scripts simple and easy. That can work, but sometimes we want to put a few things into a script to ensure that we deploy all the changes at once. In the last article, I had this list of changes in one script.

    2026-01_0168_thumb[1]

    I generated this in the last post with a poor name.

    2026-01_0175

    Let’s fix that.

    Using the Power of AI

    I’m going to delete that script and get my list of objects in the Generate tab. I’ll select a few, as shown below.

    2026-01_0177

    Now I’ll generate the script.When the script completes, I see my default “Steve” name for the description. However, look to the right. There’s a looping circle at the far right side of the Description box. I didn’t capture a good image, but it’s actually moving in a circle.

    2026-01_0178

    When it completes, I have a better description for my changes.

    2026-01_0179

    Let me save this and repeat it for the other changes to the customer tables.

    2026-01_0180

    That’s a way better description than I would typically write.

    Enabling AI Features in Flyway

    This is a preview feature as of Jan 5, 2026 as I write this. To get this in your FWD, your organization needs to have enabled AI features in your portal. I’m just a member, but whoever is an admin for your Redgate products would find it here.

    2026-01_0173_thumb[1]

    In FWD, you need to look at the Preview Features item under the config menu.

    2026-01_0171_thumb

    In this area, you can enable or disable features as needed. I see these marked as Red-gate only, but I think they are supposed to be released to some customers by this time. It’s likely I need to upgrade my FWD, which I’ll do when I have time.

    2026-01_0172_thumb[1]

    Once you do this, you should start seeing some AI stuff with the purple/pink shaded area and the sparkle icon that we’re all seeing everywhere.

    2026-01_0174_thumb

    Summary

    Getting good migration script descriptions, or really any good descriptions, is hard. Developers get tired, they aren’t always creative, they forget things, and they sometimes just take the default.

    Witness my repo.

    2026-01_0181

    This feature reduces the burden on developers and auto-generates a name for the file. It can be edited and changed, but the dev doesn’t have to.

    This feature is documented, but we are likely to enhance and change it a bit, so all feedback is welcome. If your organization doesn’t want you using AI, and you could share some schema from a migration script, I’d be happy to test it for you and see what summary is produced and send it back to you. Ping me on X/LinkedIn/BlueSky if you want.

    Flyway is an incredible way of deploying changes from one database to another, and now includes both migration-based and state-based deployments. You get the flexibility you need to control database changes in your environment. If you’ve never used it, give it a try today. It works for SQL Server, Oracle, PostgreSQL and nearly 50 other platforms.

    Video Walkthrough

    See a video of me looking at this feature below.