Fixing SQL Server Case Sensitivity Issues with GitHub Copilot CLI

When creating dbatools commands, most of us use case-insensitive collation because that's the default and what we use in our labs. So creating commands that call T-SQL always works on our machines, but then we'll get an issue requesting that we fix a command to work on someone's case-sensitive SQL Server.
With case-sensitive collation (CS), sys.databases and SYS.DATABASES are two distinct objects.
Fixing these SQL queries usaully require me to open the command, copy the T-SQL, paste it into SSMS (which would fix the casing), then copy it back to the command.
I'd long thought about setting up a test runner with case-sensitive collation, but it never happened. For projects like dbatools with T-SQL queries scattered across hundreds of files, manually fixing case mismatches is a chore.
It's a perfect task for AI, though, and I ended up trying 3 different approaches.
Get a reference list first
Before any AI can fix case sensitivity, it needs to know the correct casing. For projects using only system objects (like dbatools), I exported the canonical names and wrote them to disk:
1$query = "SELECT DISTINCT
2 SCHEMA_NAME(schema_id) + '.' + name AS FullName
3 FROM sys.system_objects
4 WHERE SCHEMA_NAME(schema_id) IN ('sys', 'INFORMATION_SCHEMA')
5 UNION
6 SELECT DISTINCT SCHEMA_NAME(schema_id) + '.' + name
7 FROM sys.system_views
8 WHERE SCHEMA_NAME(schema_id) = 'sys'
9 ORDER BY FullName"
10
11Invoke-DbaQuery -SqlInstance sql01 -Database master -Query $query |
12 Select-Object -ExpandProperty FullName |
13 Out-File -FilePath ./sql-system-objects.txt
For projects using custom tables and views, I'd export the schema specific to the database I was working with, using dbatools:
1Get-DbaDbTable -SqlInstance sql01 -Database myapp |
2 Select-Object -ExpandProperty Name |
3 Out-File -FilePath ./custom-objects.txt
These files create a reference for the AI to use for the task.
Find files that need fixing
Once you have your reference list, the next step is to locate all PowerShell files with SQL queries. This search finds files using .Query, .Execute, or Invoke-DbaQuery, the three ways we send T-SQL queries to SQL Server:
1Get-ChildItem -Path . -Filter *.ps1 -Recurse |
2 Where-Object FullName -notmatch '\\tests\\' |
3 Select-String -Pattern '\.(Query|Execute)|Invoke-DbaQuery' |
4 Select-Object -ExpandProperty Path -Unique
I excluded test files because we don't need to handle other people's collation within our test files. Maybe one day I'll fix those queries, but not today.
Testing three approaches
I tested three AI tools on the same task. Each got identical inputs: the files to fix, a detailed prompt explaining the requirements, and the reference list.
Claude Code with Sonnet: Too thorough
First attempt used Claude Code (my current go-to) with Sonnet 4.5. It spent over 2 minutes per file, carefully analyzing context, suggesting architectural improvements, and trying to understand why each query was written that way.
For a throwaway batch task, this was overkill. I needed case fixes, not code reviews. It did too much and, weirdly, made more mistakes than usual. This is one of the first tasks that Claude Code didn't handle well.
Claude Code is built for multi-file refactoring and architectural decisions—when there's real complexity to navigate, that's exactly what you want. But for mechanical, repetitive tasks where the instructions are crystal clear, all that context-gathering just adds friction.
Claude Code with Haiku: Too unintelligent
Next, I switched to Haiku for speed. It blazed through files in 20-40 seconds but replaced schemas that shouldn't be touched and replaced them with the wrong prefix.
The speed was great but the accuracy was not good enough.
GitHub Copilot CLI with Sonnet: Just right
GitHub Copilot CLI with Sonnet 4.5 nailed it. Exciting news for those of us who already have a subscription through work. GitHub Copilot CLI (not the gh CLI) with Sonnet spent about 20 seconds per file, made accurate changes, and didn't overthink it.
Why the difference? Near as I can figure, Copilot CLI is built for discrete changes while Claude Code is meant for sweeping work. Copilot CLI acts like a focused surgical tool—it takes your prompt, applies it to the specific file, and moves on. No attempt to solve bigger problems you didn't ask it to solve. For batch operations where you already know exactly what needs to happen, that constraint turns out to be a feature. Turns out, the tooling and environment might matter as much as the model for certain task types.
In the end, of 262 files that I piped in, there was only ONE mistake that I could find with the Copilot CLI changes! All of my tests passed except for the ones associated with that query. I don't have the attention span right now to be as detail oriented as I need to be for reviewing so I ended up just deleting that branch. But at a later date, I'll reapproach.
Running the fix
Using aitools, the actual command is straightforward:
1Get-ChildItem -Path . -Filter *.ps1 -Recurse |
2 Where-Object FullName -notmatch '\\tests\\' |
3 Select-String -Pattern '\.(Query|Execute)|Invoke-DbaQuery' |
4 Select-Object -ExpandProperty Path -Unique |
5 Invoke-AITool -Prompt .\tsql-case-sensitive.md -Context ./sql-system-objects.txt
The prompt file (tsql-case-sensitive.md), which I built with Claude's help, contained instructions like:
1
2## Rules
3
41. **Keywords**: UPPERCASE (SELECT, FROM, WHERE, JOIN, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, ORDER BY, GROUP BY, HAVING, CASE, WHEN, THEN, ELSE, END, AND, OR, NOT, IN, EXISTS, AS, ON, WITH, OVER, PARTITION BY)
5
62. **System objects**: Match exact casing from `sql-system-objects.txt` (e.g., `sys.databases`, `sys.dm_exec_sessions`, `INFORMATION_SCHEMA.TABLES`)
7
83. **Built-in functions**: UPPERCASE (ISNULL, COALESCE, CAST, CONVERT, COUNT, SUM, AVG, MIN, MAX, GETDATE, DATEADD, DATEDIFF, STRING_AGG, ROW_NUMBER, RANK)
9
104. **User objects**: Do not change (databases, tables, columns, user schemas)
The context file (sql-system-objects.txt) provided the reference list of correct casings.
What I learned
GitHub Copilot CLI won because it generally does less. Claude Code kept trying to understand the broader context and improve things I didn't ask it to improve. Even when I put instructions in all caps at the start and end of the prompt: IF THERE'S NO WORK TO DO, DON'T INVENT WORK, it still rewrote some PowerShell. For a task where the instructions are "fix these specific things and nothing else," Claude Code was just too smart.
At least that weekend, anyway. Model and tool performance is known to be incredibly variable, week-to-week and maybe this week Claude Code's prompt adherance was weak.
If I needed to refactor how dbatools handles queries across the entire codebase, Claude Code would be the right tool. For batch-processing 262 files with one mechanical fix each, Copilot CLI's narrower focus was perfect. It did what I asked and stopped.
The reference list approach worked well enough that I'll use it for other batch SQL fixes. Export the correct schema, pipe files through with clear instructions, spot-check the results. One mistake in 262 files is acceptable for a first pass that I can clean up later.
Seems that sometimes, the best tool is the one that stops when you tell it to stop.