dingus

/ˈdɪŋəs/ Something whose name is unknown or forgotten

Recursive SQL

March 2022

This week I encountered SQL’s recursive query syntax1 for the first time, using the WITH RECURSIVE common table expression syntax.

Given an sample hierarchy of book genres we can build up a table of breadcumbs:

id name parent_id
1 Science Fiction NULL
2 Dystopian 1
3 Cyberpunk 2
4 Space opera 1
WITH RECURSIVE linages AS (
  -- The non-recursive base case, top-level parents only
  SELECT
    ARRAY[genres.name] AS genre_names,
    genres.id AS tail_id
  FROM genres
  WHERE genres.parent_id IS NULL

  UNION ALL

  -- Recursively join sub-genres to their parent
  SELECT
    linages.genre_names || genres.name AS genre_names,
    genres.id AS tail_id
  FROM genres
  INNER JOIN linages ON genres.parent_id = linages.tail_id
)

SELECT ARRAY_TO_STRING(linages.genre_names, ' → ') AS breadcumb
FROM linages;

The result contains every generation of the recursion.

breadcumb
Science Fiction
Science Fiction → Space opera
Science Fiction → Dystopian
Science Fiction → Dystopian → Cyberpunk

Early in my career I saw SQL as something to avoid or abstract away, but with time I’ve come to love munging data using SQL.