sql >> Database >  >> RDS >> PostgreSQL

Postgres recursieve query met row_to_json

Sorry voor het zeer late antwoord, maar ik denk dat ik een elegante oplossing heb gevonden die een geaccepteerd antwoord op deze vraag zou kunnen worden.

Gebaseerd op de geweldige "kleine hack" gevonden door @pozs, kwam ik met een oplossing die:

  • lost de situatie van "schurkenbladeren" op met heel weinig code (gebruikmakend van de NOT EXISTS predikaat)
  • vermijdt de hele niveauberekening/conditiedingen
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

Bijwerken :

Getest met zeer eenvoudige gegevens, het werkt, maar zoals posz opmerkte in een opmerking, met zijn voorbeeldgegevens, zijn enkele frauduleuze bladknooppunten vergeten. Maar ik ontdekte dat met nog complexere gegevens het vorige antwoord ook niet werkt, omdat alleen malafide leaf-knooppunten met een gemeenschappelijke voorouder met "max level" leaf-knooppunten worden gevangen (wanneer "1.2.5.8" er niet is, " 1.2.4" en "1.2.5" zijn afwezig omdat ze geen gemeenschappelijke voorouder hebben met een "max level" bladknooppunt).

Dus hier is een nieuwe propositie, waarbij het werk van posz met het mijne wordt gemengd door de NOT EXISTS te extraheren subverzoek en er een interne UNION van maken , gebruikmakend van UNION de-duplicatie-mogelijkheden (gebruikmakend van jsonb-vergelijkingsmogelijkheden):

<!-- 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;

Getest op http://rextester.com/SMM38494;)



  1. MySQL-zelfstudie - Een beginnershandleiding om MySQL te leren

  2. Oracle Dynamic Pivoting

  3. MySQL-prestaties:MySQL versus MariaDB

  4. MET CONTROLE BEPERKING TOEVOEGEN gevolgd door CONSTRAINT CONTROLEREN vs. BEPERKING TOEVOEGEN