Tuesday, November 10, 2026

TSQL Tuesday # 204 - Are Blogs Still Relevant?

This month's T-SQL Tuesday #204 is hosted by Jeff Iannucci at desertdba.com. Find the invitation at https://desertdba.com/t-sql-tuesday-204-are-blogs-still-relevant/.
#tsql2sday

The invitation
For this T-SQL Tuesday, I’m asking folks to share why they do or don’t think the blog platform is still relevant for those of us working with databases.

Way back in the yester-year of 1999, I made an accidental switch from a fledgling airline pilot to a programmer. My background was in aviation. My education was in aviation. But I had always been a geek at heart.

Back in the '80s, I taught myself how to program in BASIC on a Commodore 64 using one of the most important blogs of the day, Family Computing Magazine. And even though I was flying airplanes, I kept reading geeky magazines and reading posts on various CompuServe forums.

And then, right before I became a professional geek, I discovered the thing called the Internet. It was so cool. You could put up all sorts of documents about all sorts of different things. But, alas, to actually learn most of the things I needed to learn through my conversion to fledgling geek, I had to peruse those very heavy blogs called Manuals.

GeoCities in 1999
Credit: WebDesignMuseum.org
They were bulky, but I could carry them around with me. However, they weren't very easy to keep up to date. So began my deeper dive into the early internet to track down errata pages and ultimately the Forums associated with whatever I was working with. Those Forums kept getting bigger and many of the more popular names from those forums started to branch out and put up their own personal websites that contained the things they used to write in the forums about. But with a lot more detail.

Even in those early days, there was a lot of plain bad information out there. A personal page of someone you trusted gave you a reference where you could be sure you'd find legit information.

I didn't realize at the time that I had watched "blogs" being born.

TIME PASSES...

I'm a self-taught guy. I didn't go to school to be a programmer or to learn how to work with databases. I've had little formal training in the tech realm. Most everything I know, I've learned myself, mostly through reading the work that other people have written, trying to do it myself, then going back to try to find out how I can do the things I needed to do even better. And occasionally falling down enough rabbit holes that I learned way more things than I ever thought I wanted to know about.

I can honestly say that without blogs, I probably wouldn't be where I am today.

Way back in 2015, a friend of mine put out a call to arms to get people to write more. I did my best to answer that call, and jabberings.codefumonkey.com was born with grand plans. Unfortunately, those plans didn't exactly come to as much fruition as I wanted. My first post there was about how I wanted to write more: at least once a week. I mostly did it my first year, but then fell off. A lot.

One of the best ways to get into writing is to write about the problems you solved at work. I don't want to make excuses, but I have spent the vast majority of my career working under strict NDAs, data protection laws or in government secure environments. There wasn't a lot I was allowed to say about what I was working on. So I was a much bigger consumer than a contributor. Still though, blogs have been a massive part of my career.

Moving into modern times, the question was, "Are blogs still relevant?".

I think the answer is a resounding "Yes". But the way they are being consumed (at least by me) has changed tremendously.

I still am a regular reader of Brent Ozar's blog, primarily because I subscribe to his website and am reminded when he posts. Makes it easy. And I'll branch off from some of the links he posts to read other things that grab my attention.

But the vast majority of my data consumption comes through Googling or ChatGPTing a problem I have and then sometimes following the links that are referenced in the answers.

And this is where I think good blogs are probably more important than ever. You probably won't get as many direct subscribers to your blog as you used to. It's just too easy to ask whatever flavor of LLM you prefer to help you with your issue. But it's those good blogs that allow those LLMs to give you the good answers. Otherwise, if the LLMs never get new content to learn from, you just keep getting the same stagnant slop.

I think that makes it much more difficult, if not nearly impossible, to truly monetize your blog in such a way that allows you to quit your day job. But I think if that's what you were doing it for, you were probably doing it wrong.

I still think good content creators deserve some sort of compensation for the knowledge they share, but I'm not sure what that looks like in our current environment. I know it's not much, but I will happily do my part and buy a round of beer (or ++) if I am in the company of one of the bloggers who have helped me get my job done. Even if that answer was originally sourced from ChatGPT.

One of the values that was instilled into me way back during my days of flight instructing is that I want to share the things I've learned so that the people who come after me can learn from the things I did wrong, rather than have to make the same mistakes themselves.

I'm glad there are people out there who enjoy writing. Who enjoy sharing the information they've learned. Who put in the effort to make regular content. I unfortunately found out that I only meet two of those things, but the people who do all three are the ones who make my job and my life so much easier.

Thank you.

Wednesday, July 30, 2025

I'm Speaking At PASS Data Community Summit!


A few years ago, I had the privilege of speaking virtually at PASS Summit. I have had the great fortune to be select to be an in-person speaker this year. I'll be presenting my I'm Just Here For The T-Shirt talk about Impostor Syndrome. 

I love this topic. It has most definitely had a major impact on pretty much my entire career as a tech person. I say that I'm professionally trained to be an airline pilot, and that was the direction I originally thought I was going in. But at this point, I've spent SIGNIFICANTLY more geek time than I did pilot time. You'd think I'd feel a bit better about myself. 

But, alas....

My Impostor Syndrome talk has always been one that has garnered some attention. I'm guessing it'll be the same at PASS. It'll just be a much bigger audience this time. 

Goody.


But if you're in the Seattle area in the middle of November, come on out.  https://passdatacommunitysummit.com


Summit Schedule


LinkedIn Intro Post




Sunday, June 15, 2025

Saturday, June 14, 2025

SQL Exercise From Brent Ozar

This is coming from:  https://www.brentozar.com/archive/2025/06/query-exercise-return-routes-in-the-right-order/

I started this exercise when Brent first posted it, but misread the directions at first and accidentally got most of the right answer, but in the wrong way. I wasn't really selecting the true next Station, I was just iterating through them all and picking up the one that should be next. So I set it aside and forgot about it.

Now that all the answers are out, I was reminded that I needed to finish. Before looking at the answers, I went back to try my hand again. I went a recursive CTE route, but I was unhappy with the Query Plan. I did get the right answer, but it looked gross to me. However, it worked, and it was fewer than 20 lines, so I wasn't too unhappy. It did take me much longer to noodle through than it should have: about 2 hours, going down a couple of wrong paths before I finally found one I was happy with.

; WITH StationList AS (
  ---- GENERATE THE LIST WITH THE NextStationName.
  SELECT s.StationID
     , s.StationName
     , s.StationPhysicalOrder
    , COALESCE( sro.StationToName, LEAD(s.StationName) OVER (ORDER BY s.StationPhysicalOrder) ) AS NextStationName
     ---- If there's an Override Station, use that. Otherwise use regular Station.
  FROM Stations s
  LEFT OUTER JOIN StationRoutingOverride sro ON sro.StationFromName = s.StationName
)
, NO2 AS (
  ---- RECURSIVE CTE TO GET NEXT STATION
  SELECT sl.StationName, sl.NextStationName, rn=1
  FROM StationList sl WHERE sl.StationName = 'A'
  ---- sl.StationName can be changed to start from any station.

  UNION ALL

  SELECT sl2.StationName, sl2.NextStationName, rn+1 AS rn
  FROM StationList sl2
  INNER JOIN NO2 ON no2.NextStationName = sl2.StationName
  ---- Last StationName will have NULL NextStationName and stop the recursion.
  WHERE rn <= 99 ---- To prevent infinite loops
)
SELECT StationName FROM NO2

When I looked at some of the other answers, I was pretty impressed. Swarts STRING_AGG() was pretty cool, and I was glad to see that a lot of the other answers went the recursion route.

I decided to see how mine performed, so I ginned up some more data into the tables to throw at these queries. I dumped a million rows into the Stations table, using

INSERT INTO Stations (StationName, StationPhysicalOrder)
SELECT CAST( NEWID() AS varchar(50) ), n
FROM numbers
WHERE n > 19

to generate some extra (hopefully unique) data. Then created about 500 Override rows. I figured this would give the queries some pretty decent exercise.

DROP TABLE IF EXISTS #tmpInsertOverrrides1
CREATE TABLE #tmpInsertOverrides1 ( rn int identity, f varchar(50) )

DROP TABLE IF EXISTS #tmpInsertOverrrides2
CREATE TABLE #tmpInsertOverrides2 ( rn int identity, t varchar(50) )

INSERT INTO #tmpInsertOverrides1 (f)
SELECT StationName
FROM stations
WHERE StationID IN ( SELECT TOP 500 n FROM numbers ORDER BY NEWID() )

INSERT INTO #tmpInsertOverrides2 (t)
SELECT StationName
FROM stations
WHERE StationID IN ( SELECT TOP 500 n FROM numbers ORDER BY NEWID() )
AND NOT EXISTS (SELECT 1 FROM #tmpInsertOverrides1 WHERE f = StationName)

SELECT * FROM #tmpInsertOverrides2

INSERT INTO StationRoutingOverride (StationFromName, StationToName)
SELECT f, t
FROM #tmpInsertOverrides1 t1
INNER JOIN #tmpInsertOverrides2 t2 ON t1.rn = t2.rn

Again, I tried to be careful to make sure that I didn't have any dupes and that I didn't create any infinite loops. I haven't really done much more than a cursory check on the data to make sure it's good.

I reran my query against the beefed up data. Mine ran in about 2:23 and returned 100 rows. But that was also with the Query Plan turned on.

I tried the string stuffing query, but it broke because my string was too long. (STRING_AGG aggregation result exceeded the limit of 8000 bytes. Use LOB types to avoid result truncation.) That was my fault with the test data. Next one I tried was the function-based approach. But after 13 minutes, I abandoned that one. I'm still not sure if it was something in my data. The query still looks pretty cool. Michael Swart has some pretty cool query ideas.

I tried the Ugly Stations one from Greg Dodd. That one exceeded max recursion, so I didn't fully test at one. Again, the query met the rules, this was my ridiculous data that I threw this at.

I next tried Ilya Makarov's CTE solution. The OUTER APPLY solution was pretty slick. I had initially tried an OUTER APPLY but couldn't get it to work like I wanted. This one ran for almost 2 minutes before it too hit Max Recursion and failed. Again, my data's fault.

Then came Michael Bogdanov's answer. It too crashed on Max Recursion, but it did it in just 7 seconds. This one was flying.

The last one I tried was the Brute Force version by Brian Boodman. It ran for over 7 minutes before I had to kill it. It angered my SSMS.


This was an interesting exercise. And all of these answers followed the rules as they were laid out. Things didn't get weird with some of them until I threw a stupid amount of data at them. That'll cause any query to break, if it wasn't intended to run against that data.

To be fair, the first time I ran my query against the bulky data, it too crashed on Max Recursion. So I took a couple of minutes to refactor part of it and put in a check to stop it if it recursed too far. I'm kind of impressed that it actually finished. And after seeing that it finished quicker than some of the others, I'm not as disappointed with it as I was at first. But again, I also had a bit of an insider's view of the new data I added. That wasn't in the original requirements, so please nobody take this as me bashing their queries. I changed the rules at the end game, and I'm impressed with most of the answers to the given problem. I have a tendency to over-think the negative possibilities which often leads me to over-engineer the solution to the problem.

I think I may have been a bit overzealous with my fake data.


Also, be sure to check out Brent's fantastic blog.

Brent Ozar

Wednesday, October 2, 2024

My Presentation At ColdFusion Summit 2024


I recently completed my presentation on Impostor Syndrome, I'm Just Here For The T-Shirt, at Adobe ColdFusion Summit 2024. Several people asked me for the link, so here it is: https://slides.com/codefumonkey/hfts-cfs24

I had a great turnout and received some very good questions and complements after my session. I gave away a copy of Valerie Young's book, but I apologize, because I forgot to write down the recipient's name, so please shoot me an email if you see this. 

I'll also do my best to post my write-up of the conference after I get home. 

 Thank you to Adobe for hosting a great conference. 

 And a Great Big Thank You to those of you who came out to my session!

Saturday, January 13, 2024

Another Holiday Puzzle - Hanukkah of Data - Speed Run

Hanakkuh of Data

A database puzzle

** WARNING: SPOILERS AHEAD **

** SPEEDRUN **

The SpeedRun wasn't a whole lot different than the original run through. There was a new, slightly more complex dataset, but the problems were almost exactly the same.

** PART 0 **

The code to unlock the files was the same as the previous set.

** PART 1 **

This one was also the same, but with the new data, it returned a different person to seed the rest of the problems with.

** PART 2 **

This one was also very similar, but the initials of the Contractor were different. There was also a slight change in the product SKUs that neded to be applied.

** PART 3 **

Since the person from the previous query changed, we had to change that value in the speedrun query. It also changed the birthdate of the Neighbor, so that required a couple of seconds of Google-fu to find dates for Libras in The Year of the Goat.

** PART 4 **

This one didn't require any changes. It pulled up different results, but otherwise was the same as the regular queries.

** PART 5 **

I had to run this one twice. This was the only one that I missed on the first try. I didn't catch that the Cat Lady was no longer in "Staten Island". My initial try gave me the wrong person, but when I removed that condition, I got the correct answer.

** PART 6 **

This one required no changes. I just returned a different person who was used in Part 7.

** PART 7 **

This one took me the longest of all of these. The data changes required me to make a few additions to the query. I changed the customer.id in the WHERE filters and added two new SKUs (HOM and TOY). There was an issue with my JOIN condition where I spit out the colors, but removing that condition gave me the right answer. Since color was such an important part of the original query, I'm guessing that this condition was probably intended, but I got lucky with my query. I'll take another look at this one, but for now, I've got the right answer.

** PART 8 **

The final question once again didn't require any changes.

The Speed Run was also pretty fun, but since the questions were essentially the same, not a lot of figuring was required for the queries. I don't know if that just means the data wasn't that much different or that I just wrote the queries originally that caught issues that were introduced in the speed run.

It took me 31 minutes to complete, and I only had one wrong answer in Part 5.





BACK TO PART 1
BACK TO PART 2
BACK TO PART 3
BACK TO PART 4
BACK TO PART 5
BACK TO PART 6
BACK TO PART 7
BACK TO PART 8

Thursday, January 4, 2024

Another Holiday Puzzle - Hanukkah of Data - Part 8

Hanakkuh of Data

A database puzzle

** WARNING: SPOILERS AHEAD **

** DAY 8 - THE COLLECTOR **

"Oh that damned woman! She moved in, clogged my bathtub, left her coupons all over the kitchen, and then just vanished one night without leaving so much as a note.

Except she did leave behind that nasty carpet. I spent months cleaning one corner, only to discover a snake hiding in the branches! I knew then that she was never coming back, and I had to get it out of my sight.

"Well, I don't have any storage here, and it didn't seem right to sell it, so I gave it to my sister. She wound up getting a newer and more expensive carpet, so she gave it to an acquaintance of hers who collects all sorts of junk. Apparently he owns an entire set of Noah's collectibles! He probably still has the carpet, even.

"My sister is away for the holidays, but I can have her call you in a few weeks."

The family dinner is tonight! Can you find the collector's phone number in time?

This is the final day, and it seems way too easy. The only things that look like clues are the statement about the acquaintance who collects all sorts of junk and that he owns an "entire set of Noah's collectibles". This seems like I'm looking for someone who purchased a lot of the items that are labeled 'Noah%'.

What we know:

  1. The Collector has an entire set of Noah's collectibles.

So first, I need to look at the products to verify which ones are Noah's Collectibles.


        SELECT * FROM products WHERE descr LIKE 'Noah%' OR sku LIKE 'COL%'
    

This shows that I won't be able to use products.sku, because some of the items are listed under 'COL%' and some under 'TOY%'. All of the 'COL' items are Noah's Collectibles, but the 'TOY' items aren't. But it does look like I can grab all of the collectibles if I just use product.descr LIKE 'Noah%`. Of course, this is another assumption on my part. Are the 'TOY's also Collectibles, or is it just items listed with 'COL'?

    SELECT c.customerid, c.name, c.phone
    FROM customers c
    INNER JOIN (
        SELECT TOP 1 o.customerid, count(*) AS cnt
        FROM orders o
        INNER JOIN orders_items oi ON o.orderid = oi.orderid
        INNER JOIN products p ON oi.sku = p.sku
            AND p.descr LIKE 'Noah%'
        GROUP BY o.customerid
        ORDER BY cnt DESC
    ) s1 ON c.customerid = s1.customerid

Entering the phone number shows this is correct, too.

All days have been completed.


"Oh yes, that magnificent Persian carpet! An absolute masterpiece, with a variety of interesting animals congregating around a Tree of Life. As a collector, I couldn't believe when it fell into my lap.

"A friend of mine had taken it off her brother's hands, and she didn't know what to do with it. I saw her one day, and she was about to put an old rug out at the curb. It looked like it had been through a lot, but it was remarkably not that dirty. It still took quite a bit of effort and no small amount of rug cleaner, but ultimately, I managed to get the last bits of grime out of it.

"I actually live right down the street from Noah's Market - I'm a huge fan and I shop there all the time! I even have a one-of-a-kind scale model of Noah's Ark that makes a complete set of Noah's collectibles.

"I would love for Noah to have his rug once again to enjoy."

** CONCLUSION **

These were interesting puzzles. The querying part wasn't that difficult, but just figuring out what was being asked was extremely difficult for some of these. I'm not sure that this really tested my SQL skills as much as it tested my ability to determine what it was that the customer was actually asking for.

Overall, it was pretty fun. Now that we've completed the first batch, I think I'll try to see what the speed run is like.





BACK TO PART 1
BACK TO PART 2
BACK TO PART 3
BACK TO PART 4
BACK TO PART 5
BACK TO PART 6
BACK TO PART 7
BACK TO PART 8