Tag: AI

  • SQL Server 2025 RegEx and AI

    One of the language changes in SQL Server 2025 that I’ve seen a lot of people mention is the addition of RegEx functions to T-SQL. I decided to take a few minutes and try to examine how this feature works, and how I might use it. And more importantly, can AI help?

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

    Data with a Bit of a Pattern

    One of the common things people use Regex for is validating email addresses.

    I created a basic table in a database that looks like this:

    CREATE TABLE customer
    (
         customerid INT NOT NULL
             CONSTRAINT CustomerPK PRIMARY KEY,
         customeremail VARCHAR(200),
         validated TINYINT
    )
    GO

    I then asked PromptAI to get me some test data like this:

    2025-11_line0142

    I wasn’t connected to a database, but I still got code generated with insert statements. The AI also noted I had a “validated” column, and it populated that appropriately: 1 for good email, 0 for bad ones.

    2025-11_line0143 

    Once I run the inserts, I have data.

    2025-11_line0145

    Now, can I check that the AI did this correctly?

    REGEXP_LIKE

    In SQL Server 2025, there are a number of regular expression functions, and REGEXP_LIKE is one of these. This function is designed to return a boolean if the string_expression matches the pattern_expression, where the latter is the regular expression.

    2025-11_line0146

    Prompt sees this as a valid function for SQL Server 2025, which is great. I want to use the customeremail from the table as my string to check. For the regex, I need to create a regular expression, something I am not good at doing. I learned to do this at a very rudimentary level when writing Perl, but I’ve lost whatever little skill I used to have.

    I saw an expression on StackOverflow for validating email. Let’s check if an AI can help.

    2025-11_line0149

    In a few seconds, even on airport wi-fi (SFO as I write this), I get a response.

    2025-11_line0150

    This looks like the expression from the SO answer, though much shorter. If you read SO, you know that the format isn’t as set and stable as we’d like. In any case, let’s see what this shows.

    This is interesting. I get an error.

    2025-11_line0152

    If I look at the docs, this says it returns a true/false, which I’d assume would convert to a 1/0, but let’s try an explicit case. When I do this, it works.

    2025-11_line0153

    I can also do this in the WHERE clause, where the true/false thing just works. Let me move the function to the WHERE clause. If I do that, I have this code:

    SELECT customerid,
            customeremail,
            validated
    FROM dbo.customer
    WHERE REGEXP_LIKE(customeremail, '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')

    When I run this, I see what I expect:

    2025-11_0136

    Not a bad enhancement to the T-SQL language.

    Summary

    There’s a lot written on RegEx, so this post isn’t intended to delve deeply into what RegEx expressions you choose. Rather, I wanted to show the basics of this REGEXP_LIKE() function, and showcase one of the weird things I found when including this in the column list. I also haven’t looked at performance yet, though that certainly is something to be concerned about with larger datasets

    There are other changes in SQL Server 2025, and I’ll try to examine some in the coming weeks.

  • Finding and Killing Blockers with Redgate AI Tech

    Redgate has a research arm, called the Foundry, that has been experimenting with AIs and DBA tasks. This post shows how GenAI tech can be helpful to DBAs in finding blocking and removing the offending client.

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

    Redgate Runbooks

    One of the experiments the Foundry is running is with something we’ve called Runbooks. Here’s the main screen, where I have a welcome and a chat window. This is like what I see in Claude.ai.

    2025-10_line0120

    I have connected this to two instances in the settings, and given the tool permissions to run queries, but not execute commands. The first server is the Local 2022 Default and the second is the 2910-41433.

    2025-10_line0122

    A Blocking Problem

    I’m going to set up a blocking session with this code. Notice it opens a transaction and then performs an update.

    2025-10_line0110

    In a second session, I’ll run this code. Notice this select is blocked and I have no results. The bottom shows this as “executing”.

    2025-10_line0123

    Now I’ll go to the Runbooks and enter a question. In this case, I ask it what is wrong with my 2022 server, as if someone called me and said there was an issue. Imagine the “Select” query owner wondering why things aren’t returning right away.

    The Redgate Runbook responds by saying it needs to run something. The first time, it asks me to approve this, which I did. Then it runs it and shows executed.

    2025-10_line0112

    Below this I get some results of what’s returned. This isn’t different than SP_who2, but if you’ve used that tool, you often get a lot of system stuff. I Could use sp_whoisactive, but again, more results than I want without knowing anything. Here the Runbook as limited results to what I care about.

    2025-10_line0114

    What’s more, the Runbook then tells me something about what it analyzes. This isn’t perfect, but it’s been better than what a lot of help desk/first line support people have told me.

    2025-10_line0115

    If I know who 56 is, certainly I can ask them to close their tran. This isn’t perfect, but I can ask the Runbook to do this, as I do at the bottom of the image above.

    It again asks me to run something, and when it does, I see the executed note.

    2025-10_line0116

    If I go back to SSMS, I see the query completed.

    2025-10_line0124

    I typically might not kill the session without more research. I could have asked for what this is, which I’ll do now for the 57 (blocked) session. What was running here? (since 56 was killed)

    2025-10_line0117

    Again, I approve this and get results.

    2025-10_line0118

    To me, that’s pretty cool. Using AI to help me get things done as a lever, rather than a replacement is useful. I could have set the AI checking while I finished another task, or used Slack/Teams to check with others as a troubleshoot. I could certainly let the AI run, but I want approvals. I could copy/paste the code to a tool to run it, but the AI let’s this run separately, while I could be multi-tasking with a phone call to the user, or to the help desk, or anything else. More importantly, if I had this AI working from a mobile phone (jump box, etc.) I could be doing minimal typing and have the tech working for me.

    This isn’t a product, and unlikely to be one in its own right, but this is the type of thinking we do at Redgate. Harness AI, in a safe way, that’s useful.

    And ingeniously simple.

    Tom Hodgson runs the group that worked on this, and he have me a fun, unforgettable interview. You can watch here: https://www.red-gate.com/simple-talk/podcasts/coffee-chat-with-tom-hodgson/

    Video Walkthrough

    Watch this live

  • Data > Hype

    There is a ton of hype now about using GenAI for various tasks, especially for technical workers. There are lots of executives who would like to use AI to reduce their cost of labor, whether that’s getting more out of their existing staff or perhaps even reducing staff. Salesforce famously noted they weren’t hiring software engineers in 2025. I’m not sure they let engineers go, but it seems they did let support people go.

    For many technical people, we know the hype of a GenAI agent writing code is just that: hype. The agents can’t do the same job that humans do, at least not for some humans. We still need humans to prompt the AIs, make decisions, and maybe most importantly, stop the agents when they’re off track. I’m not sure anyone other than a trained software engineer can do that well.

    I was listening to a podcast recently on software developers using AI, and there was an interesting comment. “Data beats hype every time, ” which is something I hope most data professionals understand. We should experiment with our hypothesis, measure outcomes, and then decide if we continue on with our direction, or if we need to rethink our hypothesis.

    Isn’t that how you query tune? You have an idea of what might reduce query time, you make a change, and check the results. Hopefully you don’t just rewrite certain queries using a pattern because this has helped improve performance in the past without testing your choice. Maybe you default to adding a new index (or a new key column/include column) to make a query perform better? I hope you don’t do those last two.

    AI technology can be helpful, but there needs to be some thought put into how to roll it out, how to set up and measure experiments, and get feedback on whether it actually produces better code and helps engineers. Or if it’s just hype that isn’t helping.

    Ultimately, I think that this is especially true for data professionals, as the training of models on SQL code isn’t as simple or easy as it might be for Python, Java, C#, etc. For example, I find some models are biased more towards one platform (MySQL) than another (SQL Server). Your experiments should include using a few different models and finding out which ones work well and (more importantly) which ones don’t. We also need to learn where models actually produce better-performing code for our platforms.

    If you’re skeptical of AI, then conduct some experiments. Try to learn to use the tool to help you, rather than replace you. Look for ways to speed up your development, or have an assistant handle tedious tasks. I have found that when I do that, I get benefits from AI that save a bit of typing.

    From the Pragmatic Engineer podcast, the best way to deal with some of the hype on AI is with data, take a structured approach to rolling it out, throw in a lot of AB testing measures with different groups or cohorts, evaluate, and see what works well. One of the things the guest noted was that the most highly regulated and structured groups are having the most success with AI. Because they’re careful about rollout, and they are measuring everything. They’ve been measuring time spent, accuracy of tasks and more. Then they decide where and when to use AI, which might be the best advice you get.

    Steve Jones

    Listen to the podcast at Libsyn, Spotify, or iTunes.

    Note, podcasts are only available for a limited time online.

  • Creating a Striped Backup Set with AI

    I needed to test a striped backup, so I decided to ask the AI’s for help.

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

    The Problem

    A customer wanted to know if we could handle a large striped backup set. In this case, 20 files. I didn’t want to try and do this myself because I was busy at the time, so I thought I could get the AI’s to help me.

    I started with this prompt:  for a sql server database called “Sandbox” can you generate a backup command that will stripe the backup across 32 files with “sandbox” the current date/time, and a number for the backup file name?

    Local Gemma3 LLM

    I started with a local model because I had that open. I got a result that looked OK.

    2025-10_0149

    Below this I had PowerShell code to help me:

    -- Using PowerShell (example):
    # $i = 1
    # while ($i -le 32)
    # {
    #   $filename = "D:\Backups\Sandbox\_" + REPLACE(CONVERT(VARCHAR, GETDATE(), 112), ' ', '_') + "_" + $i.ToString("D3").PadLeft(3, '0') + ".bak"
    #   # Execute the backup command:
    #   Invoke-Command -ComputerName <ServerName> -ScriptBlock {
    #       & "backup.exe" -Database "Sandbox" -BackupFile "$($filename)" -BackupType "D" -Init -Format "MEDIANAME = \"Sandbox\""
    #   }
    #   $i++
    # }

    This won’t work, proving that there isn’t enough database training in some of these small models. The model does warn me this won’t work as is.

    Claude

    Since the local model was slow, and didn’t get me what I wanted, I tried Claude. Same prompt, and I got this code, which is nice in that it handles the current date time whenever I run it.

    DECLARE @BackupPath NVARCHAR(500) = 'C:\Backups\' -- Change this to your backup directory
    DECLARE @DateTime NVARCHAR(20) = CONVERT(NVARCHAR, GETDATE(), 112) + '_' + REPLACE(CONVERT(NVARCHAR, GETDATE(), 108), ':', '')
    DECLARE @BackupCommand NVARCHAR(MAX)

    SET @BackupCommand = 'BACKUP DATABASE [Sandbox] TO '

    -- Generate 32 striped backup files
    SET @BackupCommand = @BackupCommand +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_01.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_02.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_03.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_04.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_05.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_06.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_07.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_08.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_09.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_10.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_11.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_12.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_13.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_14.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_15.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_16.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_17.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_18.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_19.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_20.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_21.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_22.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_23.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_24.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_25.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_26.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_27.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_28.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_29.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_30.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_31.bak'', ' +
         'DISK = ''' + @BackupPath + 'sandbox_' + @DateTime + '_32.bak'' ' +
         'WITH COMPRESSION, STATS = 10'

    EXEC sp_executesql @BackupCommand

    I could easily then test this by adding a SELECT and commenting out the Backup command. When I do that, I see these results.

    2025-10_0150

    Note I’ve started adding some line breaks to the results so I can check things.

    Prompt AI

    I decided to try Prompt AI as well. I started with this code:

    BACKUP DATABASE sandbox
    TO DISK = ‘sandbox_20251013_x.bak’ WITH INIT

    Then I opened Prompt AI and entered this: expand this backup command to create a striped backup of 32 files, replacing the x with a number for each file

    You can see this below:

    2025-10_0148

    This got me a quick and dirty backup test.

    2025-10_0147

    2025-10_0151

    Then we need to correct the syntax.

    2025-10_0152

    Now I have a command.

    2025-10_0153

    However, this doesn’t work as I can’t use string concatenation inside the backup command. I asked Prompt AI to generate a string for this instead (from this code) and then sp_exeutesql and got this code:

    DECLARE @DateString VARCHAR(8) = CONVERT(VARCHAR(8), GETDATE(), 112) -- Format: YYYYMMDD
    DECLARE @BackupCommand NVARCHAR(MAX)

    -- Build the backup command as a string
    SET @BackupCommand = 'BACKUP DATABASE sandbox TO '

    -- Add all backup file destinations
    SELECT @BackupCommand = @BackupCommand + CASE
                                                  WHEN LEN(@BackupCommand) > 25 THEN
                                                      ', '
                                                  ELSE
                                                      ''
                                              END + -- Add comma except for first item
         'DISK = ''sandbox_' + @DateString + '_' + CAST(number AS VARCHAR(2)) + '.bak'''
    FROM master.dbo.spt_values
    WHERE type = 'P'
           AND number
           BETWEEN 1 AND 32

    -- Add WITH INIT
    SET @BackupCommand = @BackupCommand + ' WITH INIT'

    -- Execute the dynamically built command
    --EXEC sp_executesql @BackupCommand
    SELECT @BackupCommand

    That works.

    2025-10_0155

    Summary

    Both Claude and PromptAI worked, though Claude worked well with a first prompt. I continue to like the Sonnet model and find it really helpful in saving time.

    It took me longer to write this post than generate the code in 3 places and test it. In terms of saving time, Claude would have saved me at least probably ten minutes, maybe more, as I’d spend time making decisions. With Claude, I got the code in under a minute and then needed to test it.

    Always test your code. Including your AI-generated code.