How I Used Claude Code To Refactor My Stored Procedures
Video Summary
In this video, I dive into my recent experience using Cloud Code from Anthropic as part of my work on Darling Data. Typically, my videos focus on T-SQL, query performance, and database optimization—topics that are near and dear to the hearts of SQL Server enthusiasts. However, in today’s episode, I explore a different aspect by sharing how Cloud Code helped (and sometimes hindered) me with tasks like refactoring stored procedures and generating README files for my GitHub repository. While some aspects were handled seamlessly, particularly with formatting code and creating consistent READMEs, other areas required more manual intervention. For instance, when it came to refining the SP Health Parser, Cloud Code was adept at condensing repetitive checks into templates, making the code cleaner and more maintainable. However, there were challenges in certain sections of Quickie Store where the end of the stored procedure was a maintainability nightmare, requiring extensive debugging and sanity-checking post-refactoring. Overall, this experience provides valuable insights into both the strengths and limitations of AI-assisted development tools in real-world scenarios.
Full Transcript
Erik dishwaskeldarling here with Darling Data. And in today’s video, we’re going to talk about something a little bit different than what I normally talk about in my videos. Usually we’re talking about T-SQL, query performance, indexes, you know, best practices, stuff like that. In today’s video, I want to talk about something that I was doing kind of over the last couple of weeks, where I was using a new offering from the Anthropic Cloud people. called Cloud Code. It’s actually still a beta thing, to refactor and some other stuff with the store procedures that I offer for free to, like, analyze SQL Server performance. Now, the tasks that I wanted it to do were things like, like, refactor big chunks of code, especially very redundant stuff. You know, create, like, readme files, like stuff that I’m really bad at doing, like the admin work of the GitHub repo. Like, making sure that everything has readme files and they’re up to date. And then also, like, over the last couple weeks, I was working on a brand new store procedure called SP Index Cleanup. This is where Cloud Code was somewhat less successful. It was good. It was good for some things in the development of it, but not very not, very much not good at other things. So I want to talk through all that. So I’m going to talk about that. I’m going to talk about that. I’m going to talk about that. I’m going to talk about that. I’m going to talk about that. I’m going to talk about that. I’m going to talk about that. I’m going to talk about that.
You know, the first thing I tried was this an application called Cursor and that thing just choked and died on my code immediately. Like, like it couldn’t under like just didn’t get any of what I was trying to do. And worse was like the few things that like it did pick up on. I was like, cool, can you fix this? And it was like, I can’t find the file. And I’m like, but you just read from the file. Like you, you, you see the code, like you just printed the code up for me. And it was just like, yeah, but I, I can’t find the file to write to it. And I was like, huh, that is that normal. And, and, and Cursor was like, no, I think I have a bug. And I was like, oh, this is, this is a strange self-awareness for a computer program, but okay, we’re just gonna, just gonna move on from here. So I tried out Claude Codes. I was very interested in it. And I’m going to talk about kind of what it did, where it was successful and where it wasn’t. If you would like to support this channel, and I want to bring up right now, Claude Code is not free. You know, like there are a lot of LLMs that you can have basic conversations with for free. It doesn’t cost you any money. Claude Code requires like an API, like API access and credits. And there were a few times me sitting there working with Claude Code where I was just like, oh, my credit card has been charged. What was that? Oh, another 50 bucks to Anthropic.
Because you have to keep refilling credits to keep using it. If you run out of credits while you’re doing something, Claude’s like, give me my $2, right? So if you want to support my Claude Addiction, excuse me, if you want to support my Claude Addiction, there’s a link down in the video description for you to do that. If you spent all your money on Claude Code credits as well, you can like, you can comment, you can subscribe. And if you want to ask me a question privately that I answer publicly during my Office Hours episodes, you can do all that. If Claude Code is not quite good enough to take the place of all of your DBAs and developers, and you still need some help with SQL Server, you can still hire me for not for Claude credits, but you can pay me real money to do any of this stuff, health checks, performance analysis, hands on server query index tuning, dealing with SQL Server performance emergencies, and of course, battering your developers and deep frying them in SQL Server knowledge until there are fewer performance emergencies for you generally, which is always a good thing.
If you would just like to get some training from me, I have about 24 hours of it. It’s all SQL Server performance tuning training, and you can get that for about $150 once you stick that discount code onto the pile. Upcoming events, the calendar has finally filled out, and there’s a lot to talk about. SQL Saturday New York City 2025 is taking place May the 10th. Redgate is going on tour with some mini-pass events in New York City, Dallas, and Amsterdam.
Those will be in August, September, and October. All the dates are right over there. And of course, Past Data Summit is taking place November 17th to 21st in Seattle, Washington. I guess that one was always out in the air, but, you know, tis the season to start making sure everyone knows these dates, has them in their calendars, and buys the appropriate tickets.
So, with that out of the way, let’s talk about Claude Code. I think I’m going to start over here, because this one’s a little bit easier. This is the…
So, like, when you start working with Claude Code, like in a GitHub repo or something, or wherever you work with code, one thing that you can do is feed it a bunch of, like, rules to follow. So, like, when Claude first started, like, spitting out code and doing stuff, the formatting was a disaster.
So, I was like, we got to work on this. So, one of the first things I did was create this Claude.md file in my GitHub repo, so that Claude knows, like, how I want my queries to look. So, I gave it all my very particular rules about comments and naming conventions and query structure and, like, join order and all this other stuff.
And, like, how to format things so that when it spits code out to me, I don’t have to spend another, like, hour reformatting everything that it gives me. So, there’s this whole long file in here where, like, you know, it’ll, like, it’ll, like, read through this at the beginning of a session. Or if I’m like, hey, you’re messing up, check this file again, and it will, like, reformat stuff the way I like it.
It gets pretty close most of the time. It’s, you know, still not perfect. There’s still stuff that I have to, like, adjust a little bit because I’m very particular about things.
But, in general, it’s pretty good. So, after… So, with that in there, the other task that I set it to with my GitHub repo, again, the admin work that I stink at was, like, making sure that all the readme files were, like, consistent and up-to-date.
And, like, everything had one because there were a bunch of folders in here where there was nothing. Some of them still don’t have them, and that’s okay. They’re ones that I didn’t want them for.
But they’re, like, the main store procedures and stuff and, like, install all, like, all of these things have readmes now so that you can, like, figure out, like, what the procedure does. There’s, like, you know, some examples of how to run it, things like that.
So, everything now has a nice consistent readme file. And Cloud Code was great at that. Cloud Code is actually much better at, like, just spitting out good markdown than I am. One thing I was really happy with was, like, when I did the human events one, I was able to tell it, like, hey, like, there are two store procedures in here that people should care about.
Like, let’s branch them at the top so that people can get right to the one they care about. So, like, it just, like, was able to do this stuff very easily and quickly. And it added a picture in there for me.
And I was very happy with this part of it. Like, this was great. The store procedure stuff was a little bit different. Let’s start off talking about where it was mostly successful. And then we can talk about where stuff was maybe not as great.
So, like, one of the first things that I had it do in SP Health Parser, when I first wrote SP Health Parser, I was, like, really just trying to get it to a point where it worked. And it did what I wanted.
And the results that it returned were, like, you know, sensible. Like, maybe not perfect, but, like, it got the results out. I could read them. Like, they were correct. Stuff like that.
But, you know, this thing reads from the system health extended event, which is all XML, parses all the XML out, and does a lot of stuff. And, like, along the way doing that, I didn’t, like, I was more focused on making sure that I just had everything. Like, just please, God, just work.
Like, then I was on, like, making sure that the code was, like, reusable, maintainable, like, not insane. Like, just adding length to the code where it wasn’t necessary. So, there was a lot of stuff in there I was doing that was very repetitive that could be condensed down.
So, one of the first things I asked Claude to do was, like, hey, like, I do this check over and over and over again to look at this one function that reads from the extended event file called sys.fnxe file target read file. It rolls right off the tongue because in SQL Server 2017, they added this column called timestamp underscore utc. So, like, it’s a lot easier to filter on that than it is to, like, parse the XML and filter on the event date in there, which I still have to do for, like, the 2016 and earlier stuff.
But there was, like, this branch in the code for, like, hey, if we do this, then we do this. Right? But it was, like, the whole query written out.
So, one thing I wanted to do was, like, template some of the dynamic SQL so that I could just, like, based on what I find here, like, replace things and just do the right, like, run the right query, like, over and over again. So, that was one of the first things I had to do. And it was pretty good at this.
So, like, and one thing that’s cool here is that in, like, Azure, well, I don’t know about Azure SQL DB because Azure SQL DB doesn’t have the system health extended event. Again, Azure SQL DB is stupid. It’s, like, running SQL Server in safe mode.
You don’t have access to a lot of stuff that you would need to do, like, good analysis on a regular SQL Server. Microsoft’s doing it for you. Anyway.
But, like, managed instance where you can do this stuff. And, like, on-prem SQL Server, there’s a bug report about the timestamp UTC column. It’s fixed in, like, the newer versions of SQL Server because, like, in the bug report it says this will be fixed in the next major release.
So, that’s not, like, NDA 2025 stuff. Don’t yell at me about that. But, like, prior to that, you had to, like, convert the column to a date time 2 before you could filter on it.
I’ll show you what the query looks like in a minute. But, like, I wanted to make that less annoying. So, I had to create this timestamp UTC mode local variable, which is a tiny int, not a bit.
And, basically, what I do is it starts at zero. If we’re on SQL Server 2017 or up, then we add one, right, because that column exists. But we have to use the convert where clause to do anything with it.
And then, excuse me, if the product version is greater than SQL Server 2022 or we’re using managed instance, then we add another one to that, right? So, if this number is, like, zero, then we use the old, like, event date from the XML filtering. If it’s one, then we use the 2017.
And if it’s greater than one, then we use the column without the convert on it. So, that was, like, one of the first things I had to do. It was pretty good at that.
Like, everything generally worked out. And then, the other stuff that I had to do was create templates for Dynamic SQL where I could easily do some, apply this stuff. So, the templates all look something like this, where we have, like, the insert list and, like, object name stuff here.
And then, we have the time filter that I want to use here. And then, the cross apply that I want to use here because that changes, too, depending on how the query ends up. There’s this thing, but this isn’t really what I want to show you.
This is more in line with what I want to show you here where, depending on how the timestamp UTC mode thing works or looks, we do different stuff, right? So, this will do this version of the cross apply for 2017 plus. We do this version of the cross apply.
And then, if it’s, like, a version where this isn’t fixed, oops, it’s a version where this isn’t fixed. Then, we do the convert date time offset 7 before we do the filtering. And then, if it’s the version where it’s fixed, then we don’t need to worry about that.
And then, you know, like, you run the replace on stuff in here, and then you have this set up to run over and over and over again. So, once you get into, like, the actual checks, this is the logging to table stuff. We don’t need to look at this again.
We need to get down a little bit lower to where the queries start running. So, what it does now is rather than, like, rather than that query with the cross apply that we just looked at being written out over and over and over again for every different event, this thing runs a little bit differently now. We fire up a cursor.
We work off a table variable that has everything in it that I want to loop over. I think that’s just up here. Yeah.
So, this is the collection table variable that I use. So, this figures out exactly, like, which, like, area to check in, the place that I get it from, and the temp table that it goes to, right? It’s in, like, the column that I need to select from and insert and everything.
So, all this data is here now. And now, when I loop over stuff down in this cursor, I just, like, generate that insert. I run a replace on this collection SQL local variable to replace the object name and the temp table I’m inserting to and the insert list for that table.
And then I just, like, that just runs in a loop and does the insert over and over again. And, of course, like, with debug and stuff, I can print that out. And then within the cursor, I just, like, update this to say which things are done, which is important because some of these collection areas work off the same thing, right?
So, like, SP server diagnostics component result, you’ll see that a few times in here. I don’t need to run this once for each one of those. All I have to do is collect this once and then parse the XML out from that.
So, it’s very useful to just have, like, hit that once. So, I don’t need to hit this over and over and over again. So, it was very good with helping me sort of condense this down.
Like, again, not perfect. There were things that I had to, like, fix and sanity check and make sure it still worked afterwards. But, like, as far as just, like, setting up, like, the bones of things, it was very good at that.
The other thing that I had to do was in Quickie Store. So, in Quickie Store, the end of the store procedure was a nightmare, like a maintainability nightmare. The output, and it was purely for, like, the output of Quickie Store, right?
So, there were, there’s two options. There’s expert mode, which returns a bunch of extra columns in the main result set and additional tables. And then there’s format output.
And format output, like, you have big numbers. It puts commas into the numbers for you. By default, expert mode is set to zero, but format output is set to one because, like, I don’t want to have to remember to turn format to one every time I run this, which is what I do.
So, I had it create two things for me to drive the final result. They’re both table variables. And this is actually a good use for table variables, right?
So, I actually had it use table variables for something table variables are good for. And what I, like, and this took a few iterations. I don’t want to pretend like it just spit this thing out perfect on the first go. Like, there was definitely stuff that needed tweaks.
But, like, I could type in the tweaks that I needed it to make, and it would make the right adjustments. The really cool thing, too, is that, like, it wasn’t just returning code to the screen that I had to go and, like, paste into the procedure and do stuff with. It was, like, actively editing the files that were in my GitHub repo.
So, I could just, like, you know, hit submit to GitHub and, like, push stuff around. It was, it’s a little tricky right now because Cloud Code doesn’t run on Windows. At least, I couldn’t figure out how to get it to run on Windows.
I don’t think it does. But, so, like, I, like, like, sitting at my Mac over here where I have the Cloud Code terminal window running. I’m going to, like, type stuff there, push it up to GitHub, pull it down on GitHub on Windows, then run the store procedure and, like, make sure that stuff works. So, there’s a little bit of, like, crosstalk back and forth right now.
This can be a little bit awkward if you’re, if you don’t have, like, a Mac to, or something else to use this on. But I figured it was worth it for the experiment. So, it creates these table variables.
And, like, it was, like, kind of amazing at, like, like, analyzing the select list, figuring out which temp tables things came from, which columns were expressions, and, like, which conditions those, like, those columns should show up under. And, like, making a table variable to store all this stuff. So, like, all of these things have, like, like, a format pattern.
And, like, if they need one, so, for, like, down here, like, all of these, all these columns in here have the option to format them. And, no, that’s the last execution time. I’m looking for, like, duration.
So, like, when I run the format function, we use that n0, right, just to put commas into, like, with no decimal point. That’s a n0 means zero decimal places. If you can do, like, n1 or n2 or n5 or whatever if you want decimal places.
n0 is just, like, a number formatted with commas that, or whatever local thing you use. In France, it’s spaces, I found out. But, yeah, you can, like, it just put all this information in there for me.
And, like, at first, like, it was just numbering these sequentially. And I was, like, hey, if I need to insert stuff in between, can you put this in, like, can you use a different numbering scheme so that, like, if I need to put stuff in, here or reorder this, it’s not a nightmare of me having to renumber everything.
So, and it was pretty good at this. One thing that needed help was, like, some of the new columns weren’t perfect. But, like, it was able to get that once we started, like, once I started, like, you know, telling it, hey, this isn’t going to work under these conditions. We need a column to, like, direct it to this.
Then, like, we need another, like, we need to, like, let, like, another level in the case expression to, you know, make sure that it, like, does these things right. So, like, one example of those would be, like, the hash totals for physical IO reads. This was one where we had to put, like, this thing in different than the other ones.
Right. So, that’s kind of fun there. But, yeah, anyway, like, it was very good with that.
And then the other thing that I had to do was, like, use a table variable to sort of deal with all the different parameters. So, the parameters that get passed in, like, indicate different temp tables get used and created and, like, stuff like that. So, this was all very useful here.
And then, like, there was a bunch of, like, sort of very repetitive code where, like, for all of these things, like, all of, like, all of the checks to include these things or, like, alternately exclude these things were all, like, very much written out very explicitly. Like, if this, this, if this, if this, if this, if this, then this. Right.
Like, I was just able to, like, have cod template all this stuff for me. So, like, one thing that was good in there was, like, let’s get down to, actually, let’s see. Let’s just do this.
So, the cursor that runs over this part does a bunch of stuff in here. And then, like, there’s just neat logic in here, right, where it’s, like, insert into, like, I could have done, like, the replace thing. But, I don’t know.
This, this, this just, this was just fine for this. Like, insert into the temp table. Insert the column list. Then run this. And then down here, like, like, even, like, made, like, the temp table part dynamic. So, if I need to include stuff, then I use include.
Otherwise, I stick the ignore on the temp table name. It was just very successful at doing all this. And then, way down at the bottom, this was where stuff got more interesting, I think. Was it dynamically builds up the column list based on this, right?
So, like, the column SQL is, like, if format output is zero, then we don’t do anything to it. If format output equals one, then when the format pattern is not null, we put wrap stuff in the format function. And, like, you know, based on this crazy where clause for stuff, then we do certain things in here.
And then, like, in here, we just insert the column list, right? So, like, we just tack the column list onto the SQL and then, like, do the rest of the from clause down here. I was able to do something fairly similar with the expert mode output, but I did not go as deep as that with it.
This, I was just like, you know what, we’re just going to do, like, because, like, with the format stuff in these queries specifically, it’s weird because, like, the columns are sort of interspersed. So, like, it didn’t make as much sense to do the table variable thing.
So, in here, it’s just, like, if format output equals one, then we, like, put this in there. Otherwise, you put this in there, and then we have this other column, and then this other column. And, like, you know, so, like, there was just a lot of, like, templating stuff that made sense, like, locally for this that didn’t make sense for the other parts.
Now, this was all the stuff that it was pretty good at. But in SP index cleanup, kind of what I tried to do with it was be like, hey, like, I need to, like, this is, like, the goal of my query. Like, what would I, like, how should I structure this to, like, give me what I want, right?
Like, what’s a good way to do this? And one of the first things I came up with was this insane cursor that just, like, never turned correct results. So, I was, like, like, I got to scrap this.
I’m going to, like, just write, like, very, like, procedural, like, like, rule check updates. And then there were, like, a lot of things that I had to fix to, like, make sure that the next update worked. Claude was a little less good at this.
It was helpful, but, like, like, it required a lot of me, like, like, looking at things, analyzing things, doing stuff. Where Claude did become helpful in this part was, like, like I said, like, coming up with, like, unit test indexes to make sure that all the rules that I cared about were being adhered to. And then one of the neat things that you can do, or rather that I did here, was I was, like, okay, like, based on the indexes you gave me.
One other thing that I had at Spitout, too, was, like, one thing that SP Index Cleanup does is, like, it ignores unused indexes for deduplication. So, like, they’re unused. We’re just going to disable them.
So, one thing that I had to do was, like, spit out queries that forced, like, a select count from the table using a specific index, right? And so, like, if there was a filtered index, it would put a where clause in there that matched the filter expression. So, like, it did a lot of cool things here.
But, like, one thing that I had, one thing I did was, like, I would take the final results of the query, like, hey, these are the actions that SP Index Cleanup is now saying I should take based on these indexes. Like, here’s all the data that I have. We could, like, paste in the table data.
Like, do the results match up with what I want? And, like, it was, like, a few times it was, like, no, no. Like, this is messed up. Like, one thing that I caught early on was, like, one thing I wanted SP Index Cleanup to do was differentiate between a column sort order and the key of the index. So, like, there was an index on reputation ascending and an index on reputation descending.
And one of the first bugs I caught using that method was that it was still saying that, like, those were duplicates when they were, like, I don’t want them marked as duplicates for safety reasons. So, it was able to actually caught that in the results output and was, like, I don’t think this rule is being followed. Like, we should fix that.
So, like, there were some, like, good parts to it. Like, some of, like, the, like, larger strategic things, it was less, it would, like, kind of go off the rails with. But there was a lot of stuff where, like, if I was able to give it very specific instructions and, like, very targeted, like, I need to do this specific thing, it was really good. Another thing that was cool with it, and this will be the last thing I say because this video is getting kind of long at this point.
One thing that was kind of cool with it is that since it’s all working in my GitHub repository, I could actually have it take, like, various things that I do in other store procedures and integrate them quickly into the new store procedure. So, like, there are things that I do in SP Index Cleanup that are repetitive to other store procedures that I do, like, to get all databases, include databases, exclude databases. And it was very easy to be, like, hey, I use this, I want to apply this pattern to this store procedure, take the stuff that I do in this store procedure and put it into this new one.
And it could just, like, go look at, like, Quickie Store or HealthParser or, like, whatever else, bring, and, like, bring in the portions of the code that I cared about. Like, it was able to, like, follow the get all databases equals one part, like, and see the, like, where that got triggered and, like, just bring all the code over. For me, that would have been hours of, like, split window pane pasting back and forth.
So, it was, like, there are some very cool things you can do with it. Writing code from scratch, maybe not just yet. It wasn’t a great experience with that, but, like, the refactoring and the tweaking the refactoring and the, like, applying patterns from one store procedure to another, that was all very good.
So, if you have, if you’re interested in cloud code and seeing what it can do for you in these sort of situations, like, you know, like, even just, like, hey, find where there’s redundancy in this code. Like, it was pretty good at identifying that stuff. But, you know, there are some times, like, you still have, like, you still have to babysit this stuff a lot and be, like, and, like, sanity check it a lot because some of the stuff it comes back with is bonkers.
Right? Like, like, it was still giving me, like, in, like, invalid columns that don’t exist in, like, select lists and stuff. And I was, like, but you can see everything.
So, you know, at this point, like, like, it was able to do some impressive things. But, again, you have to give it very specific, very targeted, like, you have to, like, basically tell it exactly what to do before it does it, like, correctly and to the spec you want. And it really helps to have, like, a list of rules that it has to follow for formatting so that it doesn’t just spit ugly-ass queries out at you.
But a lot of good, a lot of good. I think it did save me a lot of time. And it actually made it possible to do this stuff.
Otherwise, I probably wouldn’t have done some of this stuff. So, like, it was a very helpful sort of, like, companion in this adventure. But, again, there is a lot of hand-holding here still.
Not the end of the world. Like, not like you shouldn’t do it. But, you know, just be prepared to, like, you know, you’re actually teaching this thing how to do something right kind of deal. And it has a short memory and it’ll forget how to do something right the next time.
So, you do have to be careful. But, overall, pretty good time. Pretty fun experiment. It got a lot of good work done that I’m happy with. So, you know, I can’t, I can’t, I’d probably give it, like, a 7 out of 10 as far as, like, you know, nailing it type stuff.
But I think, you know, like, again, this is still in beta. So, is it, that gets better and, you know, stuff improves and I’m sure this will get better. One thing that is kind of annoying is, like, how long it takes to do some stuff.
And how many times you have to, like, hit okay for it to do something. Like, there are some times when it would spin for, like, five minutes to produce, like, five lines of code. Which I didn’t understand.
I have no idea what you’re doing. Other times, like, you would ask it to do a specific thing and it would be like, well, let me look at 50 other things. And you’re like, no, no, no, no, no. You’re not wasting time on that. I gave you this one thing to do. You don’t need to check every other store procedure and everything else.
And then there are things like, you know, like, there are some things where you can be like, don’t ask again for this session. But there are some commands where you have to, like, keep coming back and hitting okay. So, there are times when I’d be like, oh, I’m going to hit okay and go over here and do some stuff.
And then I’d look back and, like, just realize it was just sitting there waiting for me to hit okay again to do something. So, you know, again, not end of the world type stuff. Just, like, you know, kind of like, I don’t want to keep context switching to tell you it’s okay to do this.
Just do it. Like, you can’t say something like, just do this all unprompted. Like, don’t ask me any more questions.
Because it’ll say, okay, and then still ask you questions. So, you know, it is junior developer-y in a lot of ways. But it can be a very productive junior developer. So, I would suggest trying it out.
I don’t get anything from Claude Code or Anthropic or anything like that for telling you that you should probably try it out. But, you know, it’s a good time. I had fun.
Sort of. I didn’t sleep much the last couple weeks. Just getting back into a normal sleep schedule now, kind of. Because there were a lot of late nights working on SP Index cleanup. So, yeah.
Anyway, thank you for watching. I hope you enjoyed yourselves. I hope you learned something. And I will see you in another video. After I have cut my breath. Goodbye.
Going Further
If this is the kind of SQL Server stuff you love learning about, you’ll love my training. Blog readers get 25% off the Everything Bundle — over 100 hours of performance tuning content. Need hands-on help? I offer consulting engagements from targeted investigations to ongoing retainers. Want a quick sanity check before committing to a full engagement? Schedule a call — no commitment required.