PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Permintaan rekursif postgres dengan row_to_json

Maaf atas jawaban yang sangat terlambat tetapi saya pikir saya menemukan solusi elegan yang bisa menjadi jawaban yang diterima untuk pertanyaan ini.

Berdasarkan "retas kecil" yang luar biasa yang ditemukan oleh @pozs, saya menemukan solusi yang:

  • memecahkan situasi "nakal daun" dengan kode yang sangat sedikit (memanfaatkan NOT EXISTS predikat)
  • menghindari perhitungan/kondisi seluruh level
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

Perbarui :

Diuji dengan data yang sangat sederhana, itu berhasil, tetapi seperti yang ditunjukkan posz dalam komentar, dengan data sampelnya, beberapa simpul daun nakal dilupakan. Tetapi, saya menemukan bahwa dengan data yang lebih kompleks, jawaban sebelumnya juga tidak berfungsi, karena hanya simpul daun nakal yang memiliki nenek moyang yang sama dengan simpul daun "level maksimum" yang ditangkap (ketika "1.2.5.8" tidak ada, " 1.2.4" dan "1.2.5" tidak ada karena mereka tidak memiliki nenek moyang yang sama dengan simpul daun "level maksimum" mana pun).

Jadi, inilah proposisi baru, menggabungkan karya posz dengan milik saya dengan mengekstrak NOT EXISTS subrequest dan menjadikannya sebagai UNION internal , memanfaatkan UNION kemampuan de-duplikasi (memanfaatkan kemampuan perbandingan 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;

Diuji pada 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. SQL:Ketika berbicara tentang NOT IN dan NOT EQUAL TO, mana yang lebih efisien dan mengapa?

  2. Mengekspor kueri PostgreSQL ke file csv menggunakan Python

  3. gem install pg --with-pg-config berfungsi, bundel gagal

  4. Cara Meningkatkan PostgreSQL 11 ke PostgreSQL 12 dengan Zero Downtime

  5. MySQL vs PostgreSQL? Mana yang harus saya pilih untuk proyek Django saya?