alt.hn

3/30/2026 at 7:11:11 AM

Good CTE, Bad CTE

https://boringsql.com/posts/good-cte-bad-cte/

by radimm

3/31/2026 at 7:43:18 AM

Use the term, never define the term, classic.

CTE stands for Common Table Expressions in SQL. They are temporary result sets defined within a single query using the WITH clause, acting like named subqueries to improve readability and structure.

by vlaaad

3/31/2026 at 7:45:00 AM

OP here, damn - that's a very good point. Can't believe I missed it.

by radimm

3/31/2026 at 8:38:55 AM

From the headline, I thought it might be about sports-related concussions!

I was morbidly curious what a "good CTE" could possibly be...

by iainmerrick

3/31/2026 at 9:56:06 AM

As someone who is not much of a sports person, now I was wondering what CTE means in sports.

Seems to be this:

> Chronic traumatic encephalopathy (CTE) is a progressive neurodegenerative disease […]

> Evidence indicates that repetitive concussive and subconcussive blows to the head cause CTE. In particular, it is associated with contact sports such as boxing, American football, Australian rules football, wrestling, mixed martial arts, ice hockey, rugby, and association football.

https://en.wikipedia.org/wiki/Chronic_traumatic_encephalopat...

by QuantumNomad_

3/31/2026 at 2:40:06 PM

Yep, that's it.

The NFL in the US has famously gone to great lengths to downplay the impact of CTE on current and retired players. And there have been several famous players who literally lost their minds as they aged, and we now know that was due to CTE. Something like 90% of ex-NFLers have it. The number is still really bad for collegiate players. And even high school players are at risk.

It was to the point that Will Smith starred in a movie about it. https://en.wikipedia.org/wiki/Concussion_(2015_film)

by alistairSH

3/31/2026 at 10:45:07 AM

Yeah - Muhammad Ali is the most famous victim (or at least likely victim, I don’t think he was officially diagnosed with CTE as it wasn’t well understood back then). In the UK, it’s gradually becoming recognised as a serious problem in rugby.

I assumed the C stood for Concussion. Wrong but also partly right!

by iainmerrick

3/31/2026 at 11:05:39 AM

I was thinking "Compile Time Execution" like Rust's const, C++ consteval functions, Zig's comptime, that sort of thing. So the good/ bad made more sense but I was still on the wrong track, yeah a definition was appropriate.

by tialaramex

3/31/2026 at 1:11:11 PM

i appreciate the way you took the feedback. i saw the domain name and immediately knew the content and context. the article did not disappoint. i come from a heavy mssql background with some postgres sprinkled in, but my current company is migrating our mssql fleet to pg and it’s nice to have a technical foundation and article to be able to truly understand and pass the differences and similarities then how the two platforms handle workload. Traditionally it’s just been multiple sides, mercilessly criticizing each other for their deficiencies, but each platform has its own strengths and its own gaps. I’m excited to be a part of this migration, and I appreciate technical articles such as this that help me articulate the broader challenges to both our executive level levels, and our developers.

edit: syntax. voice to text was liberal with the comma abuse

by swasheck

3/31/2026 at 1:22:46 PM

I read the article before the abbreviate definition inclusion as its very opening. I had never met the abbreviation before.

It'd be quite surprising the WITH statement in top a query to be the first feature to learn/use past basic SQL. Is it personal experience in some industry?

by xxs

3/31/2026 at 1:40:31 PM

While generally a fair critique, the site does have "SQL" in its name.

by mcdonje

3/31/2026 at 10:08:31 AM

Agreed. I was relieved to see this wasn’t written by Cam Skatteboro.

by tclancy

3/31/2026 at 12:27:54 PM

Yeah, I thought I was on a sports site. Cam thinks CTE isn't real and is "all in your head." Technically correct about the all in your head part.

by lizknope

3/31/2026 at 6:59:30 PM

Eh, almost every link on the homepage has an initialism or acronym in the title, and roughly none of them are actually defining the term they're using. Indeed, not to point fingers, your own submissions make the same mistake.

Sure, yes, OP should (and now has) defined the term. But at the same time it's reasonable to expect that someone reading a blog post on BoringSQL.com would already know the term just as much as we could expect people interested in Clojure would know what a REPL is.

by da_chicken

3/31/2026 at 1:39:04 PM

Your comment could have been more helpful without the first sentence. SAME content, same correction, less superiority: "CTE is an overloaded term, in this article ......"

This is a valuable comment, don't ruin it with sarcasm and rudeness.

by cpfohl

3/31/2026 at 2:30:52 PM

> Your comment could have been more helpful without the first sentence.

no it wouldn't

the whole point is to critique the post

by NooneAtAll3

3/31/2026 at 12:38:30 PM

To the author of the article. This was a really nice and educating read. You made me finally understand recursive CTEs, the org chart was a really good example. Thank you.

by oveja

3/31/2026 at 8:09:44 AM

I've always thought of CTEs as a code organisation tool, not an optimisation tool. The fact the some rdbms treats them as an optimisation fence was a bug, not a feature.

by yen223

3/31/2026 at 8:37:44 AM

Improved readability is definitely the primary benefit.

by solumunus

3/31/2026 at 8:11:27 AM

> Recursive CTEs use an iterative working-table mechanism. Despite the name, they aren't truly recursive. PostgreSQL doesn't "call itself" by creating a nested stack of unfinished queries.

If you want something that is more like actual recursion (I.e., depth-first), Oracle has CONNECT BY which does not require the same kind of tracking. It also comes with extra features to help with cycle detection, stack depth reflection, etc.

If your problem is aligned with the DFS model, the oracle technique can run circles around recursive CTEs. Anything with a deep hierarchy and early termination conditions is a compelling candidate.

by bob1029

3/31/2026 at 11:57:46 AM

> If you want something that is more like actual recursion (I.e., depth-first), Oracle has CONNECT BY which does not require the same kind of tracking. It also comes with extra features to help with cycle detection, stack depth reflection, etc.

All that is supported with CTEs as well. And both Postgres and Oracle support the SQL standard for these things.

You can't choose between breadth first/depth first using CONNECT BY in Oracle. Oracle's manual even states that CTE are more powerful than CONNECT BY

by hans_castorp

3/31/2026 at 11:33:44 AM

There's some good stuff in here. I didn't know about the issues an aggregation in a CTE can cause and haven't used EXISTS much.

Regarding recursive CTEs, you might be interested in how DuckDb evolved them with USING KEY: https://duckdb.org/2025/05/23/using-key

by mcdonje

3/31/2026 at 12:55:51 PM

That was also a great read, thanks!

by scythmic_waves

3/31/2026 at 8:04:16 AM

I wrangle databases by day, and do martial arts of an evening. Two arenas where CTEs can cause significant headaches!

by dspillett

3/31/2026 at 9:14:56 AM

Great article, I always like to structure my queries with CTEs and I was (wrongly) assuming it all gets inlined at the end. Sometimes it also gets complicated since these intermediate results can't be easily seen in a SQL editor. I was working on a UI to parse CTE queries and then execute them step by step to show the results of all the CTEs for easier understanding of the query (as part of this project https://github.com/sqg-dev/sqg/)

by uwemaurer

3/31/2026 at 9:55:23 AM

I think your assumption about inlining is essentially correct. As far as I know postgres was the last major rdbms to have an optimiser fence around CTEs.

by siddboots

3/31/2026 at 11:28:04 AM

I concur, “the Germans” have created an algorithm that completely “see through” subqueries/CTEs when planning a query. The way the query is written has no bearing on the execution.

by nraynaud

3/31/2026 at 4:21:23 PM

Sometimes easy performance trick is to split the CTE to separate queries, put the results to unlogged temporary tables and add whatever indexes the next step needs.

Obviously makes only sense for stuff like analytical queries that are not running constantly.

by jpalomaki

3/31/2026 at 4:30:05 PM

Worth underlying the OLAP versus OLTP divide you are speaking to on the close, there.

by taeric

3/31/2026 at 4:43:52 PM

An issue that has arise for me in some situations is that for more expensive/reporting queries we point to a db replica, where temporary tables are not an option.

by andsbf

3/31/2026 at 8:00:03 AM

Great post - thanks. I think the columns in the index you suggested in the pre-pg12 section are in the wrong order (that index would get used)

by qwertydog

3/31/2026 at 8:13:53 AM

Thanks - I will recheck later today.

by radimm

3/31/2026 at 4:50:35 PM

I consulted at some Indian startups. Such bad queries were written which were costing them so much compute

I just rewrote all queries with claude code and next day and compute decreased to 1/5th.

by faangguyindia

3/31/2026 at 4:45:38 PM

I just wish that SQL Server had a materialize keyword like Postgres.

I'll write some nice clean CTEs and then have to refactor it to temp tables due to the lack of materialization.

by intrasight

3/31/2026 at 1:25:23 PM

Not to sound like a broken record, but I need to echo what many other replies have already said: great article.

Embarassingly, despite thinking of myself as pretty knowledgeable with SQL, I had no idea you could nest DML statements inside a CTE. I always assumed/used DML statements as the final statement after a CTE was defined. I'm not sure if or when I might use this in the future, but it's neat to learn something new (and to be humbled at the same time).

by ctippett

3/31/2026 at 4:02:26 PM

Wow it just keeps going. Extremely thorough.

by jt-hill

3/31/2026 at 7:23:37 PM

Love CYEs, use them all the time, great article.

by BSTRhino