On Thu, Sep 17, 2026 at 2:43 PM Vik Fearing <[email protected]> wrote:

>
>
> I don't understand what the use case for UNION DISTINCT ON is. Could you
> please provide one?
>

Here it is:

I have put it here in HTML format for clarity for human readers, and also
to see what the automatically generated plaintext format looks like when I
check it on mailing list and download it back from the mailing list
archives.
1. The Canonical Sample: Shortest Path Search (WITH RECURSIVE)

The primary motivating use case for UNION DISTINCT ON (...) is
breadth-first search / shortest path pathfinding (such as in Dijkstra's
algorithm or grid traversal like Advent of Code Day 12).

Standard SQL recursion with UNION ALL and CYCLE only performs path-local
cycle detection (it prevents visiting a node already in the current descent
path). It cannot prevent exploring sub-optimal paths if another branch
already reached that node faster, resulting in a combinatorial explosion of
paths.

With UNION DISTINCT ON (r, c ORDER BY len), earlier or shorter paths to a
given key replace or prune longer paths:
Schema & Setup:

CREATE TABLE day12_test (

    rownr SERIAL PRIMARY KEY,

    data TEXT

);

INSERT INTO day12_test (data) VALUES

  ('Sabqponm'),

  ('abcryxxl'),

  ('accszExk'),

  ('acctuvwj'),

  ('abdefghi');

CREATE TABLE day12_pointmap AS

SELECT rownr AS r

     , c::int

     , h

     , (CASE h WHEN 'S' THEN 0 WHEN 'E' THEN 25 ELSE ascii(h) - 97 END) AS
height

FROM day12_test

   , unnest(regexp_split_to_array(data, '')) WITH ORDINALITY u(h, c);

CREATE UNIQUE INDEX day12_pointmap_undx ON day12_pointmap(r, c) INCLUDE (h,
height);
Query Using UNION DISTINCT ON:

WITH RECURSIVE search_path AS (

    -- Non-recursive term: Start position

    SELECT 0 AS len, *

    FROM day12_pointmap

    WHERE h = 'S'

  -- Deduplicates coordinates across all paths, keeping the minimum step
length:

  UNION DISTINCT ON (r, c ORDER BY len)

    -- Recursive term: Step to adjacent qualifying coordinates

    SELECT len + 1 AS len

         , p.r, p.c, p.h

         , p.height

    FROM day12_pointmap p

    JOIN search_path sp

      ON (p.c, p.r) = ANY (ARRAY[(sp.c, sp.r - 1), (sp.c, sp.r + 1),

                                 (sp.c - 1, sp.r), (sp.c + 1, sp.r)])

     AND p.height <= sp.height + 1

)

SELECT *

FROM search_path;

------------------------------




>
> --
>
> Vik Fearing
>
>

Reply via email to