PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Rekurencyjne zapytanie Postgres z row_to_json

Przepraszam za bardzo późną odpowiedź, ale myślę, że znalazłem eleganckie rozwiązanie, które może stać się akceptowaną odpowiedzią na to pytanie.

W oparciu o niesamowity „mały hack” znaleziony przez @pozs, wymyśliłem rozwiązanie, które:

  • rozwiązuje sytuację „nieuczciwych liści” za pomocą bardzo małej ilości kodu (wykorzystując NOT EXISTS orzeczenie)
  • unika wszystkich obliczeń poziomu/warunków
WITH RECURSIVE customer_area_tree("id", "customer_id", "parent_id", "name", "description", "children") AS (
  -- tree leaves (no matching children)
  SELECT c.*, json '[]'
  FROM customer_area_node c
  WHERE NOT EXISTS(SELECT * FROM customer_area_node AS hypothetic_child WHERE hypothetic_child.parent_id = c.id)

  UNION ALL

  -- pozs's awesome "little hack"
  SELECT (parent).*, json_agg(child) AS "children"
  FROM (
    SELECT parent, child
    FROM customer_area_tree AS child
    JOIN customer_area_node parent ON parent.id = child.parent_id
  ) branch
  GROUP BY branch.parent
)
SELECT json_agg(t)
FROM customer_area_tree t
LEFT JOIN customer_area_node AS hypothetic_parent ON(hypothetic_parent.id = t.parent_id)
WHERE hypothetic_parent.id IS NULL

Aktualizacja :

Testowany z bardzo prostymi danymi, działa, ale jak zauważył posz w komentarzu, z jego przykładowymi danymi zapomniano o niektórych nieuczciwych węzłach liści. Ale dowiedziałem się, że przy jeszcze bardziej złożonych danych poprzednia odpowiedź też nie działa, ponieważ wyłapywane są tylko nieuczciwe węzły liści mające wspólnego przodka z węzłami liści „maksymalny poziom” (gdy nie ma „1.2.5.8”, „ 1.2.4” i „1.2.5” są nieobecne, ponieważ nie mają wspólnego przodka z żadnym węzłem liścia „maksymalnego poziomu”).

Oto nowa propozycja, mieszanie pracy posz z moim przez wyodrębnienie NOT EXISTS podżądanie i uczynienie go wewnętrzną UNION , wykorzystując UNION umiejętności deduplikacji (wykorzystywanie umiejętności porównywania jsonb):

<!-- language: sql -->
WITH RECURSIVE
c_with_level AS (

    SELECT *, 0 as lvl
    FROM   customer_area_node
    WHERE  parent_id IS NULL

    UNION ALL

    SELECT child.*, parent.lvl + 1
    FROM   customer_area_node child
    JOIN   c_with_level parent ON parent.id = child.parent_id
),
maxlvl AS (
  SELECT max(lvl) maxlvl FROM c_with_level
),
c_tree AS (
    SELECT c_with_level.*, jsonb '[]' children
    FROM   c_with_level, maxlvl
    WHERE  lvl = maxlvl

    UNION 
    (
        SELECT (branch_parent).*, jsonb_agg(branch_child)
        FROM (
            SELECT branch_parent, branch_child
            FROM c_with_level branch_parent
            JOIN c_tree branch_child ON branch_child.parent_id = branch_parent.id
        ) branch
        GROUP BY branch.branch_parent

        UNION

        SELECT c.*, jsonb '[]' children
        FROM   c_with_level c
        WHERE  NOT EXISTS (SELECT 1 FROM c_with_level hypothetical_child WHERE hypothetical_child.parent_id = c.id)
    )
)
SELECT jsonb_pretty(row_to_json(c_tree)::jsonb)
FROM c_tree
WHERE lvl = 0;

Testowane na http://rextester.com/SMM38494;)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zachowaj strefę czasową w typie PostgreSQL timestamptz

  2. Gdzie są logi PostgreSQL w systemie macOS?

  3. Jak tworzyć zapytania bez uwzględniania wielkości liter w Postgresql?

  4. Postgresql Wybierz wiersze, w których kolumna =tablica

  5. Funkcja z zapytaniem SQL nie ma miejsca docelowego dla danych wynikowych