sql >> Database teknologi >  >> RDS >> PostgreSQL

Postgres - Konverter tilgrænsende liste til indlejret JSON-objekt

Brug af WITH RECURSIVE (https://www.postgresql.org/docs/current/static/queries-with.html) og JSON-funktioner (https://www.postgresql.org/docs/current/static/functions-json.html) I byg denne løsning:

db<>violin

Kernefunktionaliteten:

WITH RECURSIVE tree(node_id, ancestor, child, path, json) AS ( SELECT t1.node_id, NULL::int, t2.node_id, '{children}'::text[] || (row_number() OVER (PARTITION BY t1.node_id ORDER BY t2.node_id) - 1)::text,-- C jsonb_build_object('name', t2.name, 'children', array_to_json(ARRAY[]::int[])) -- B FROM test t1 LEFT JOIN test t2 ON t1.node_id = t2.parent_node -- A WHERE t1.parent_node IS NULL UNION SELECT t1.node_id, t1.parent_node, t2.node_id, tree.path || '{children}' || (row_number() OVER (PARTITION BY t1.node_id ORDER BY t2.node_id) - 1)::text, jsonb_build_object('name', t2.name, 'children', array_to_json(ARRAY[]::int[])) FROM test t1 LEFT JOIN test t2 ON t1.node_id = t2.parent_node INNER JOIN tree ON (t1.node_id = tree.child) WHERE t1.parent_node = tree.node_id -- D ) SELECT -- E child as node_id, path, json FROM tree WHERE child IS NOT NULL ORDER BY path

Hver WITH RECURSIVE indeholder en start SELECT og en rekursionsdel (den anden SELECT ) kombineret med en UNION .

A:At slutte sig til tabellen mod sig selv for at finde børnene til en node_id .

B:Opbygning af json-objektet til barnet, som kan indsættes i dets overordnede

C:Byg stien, hvor det underordnede objekt skal indsættes (fra rod). Vinduesfunktionen row_number() (https://www.postgresql.org/docs/current/static/tutorial-window.html) genererer indekset for barnet i forælderens børnearray.

D:Rekursionsdelen fungerer som den indledende del med én forskel:Den søger ikke efter rodelementet, men efter elementet, som har moderknudepunktet for den sidste rekursion.

E:Udførelse af rekursion og filtrering af alle elementer uden nogen underordnede giver dette resultat:

node_id   path                      json
2         children,0                {"name": "node2", "children": []}
4         children,0,children,0     {"name": "node4", "children": []}
5         children,0,children,1     {"name": "node5", "children": []}
6         children,0,children,2     {"name": "node6", "children": []}
3         children,1                {"name": "node3", "children": []}
7         children,1,children,0     {"name": "node7", "children": []}
8         children,1,children,1     {"name": "node8", "children": []}
 

Selvom jeg ikke fandt nogen måde at tilføje alle underordnede elementer i rekursionen (oprindelsen json er ingen global variabel, så den kender altid ændringerne af de direkte forfædre, ikke deres søskende), var jeg nødt til at iterere rækkerne i et sekunders trin.

Derfor bygger jeg funktionen. Derinde kan jeg lave iterationen for en global variabel. Med funktionen jsonb_insert Jeg indsætter alle beregnede elementer i et root json-objekt - ved hjælp af den beregnede sti.

CREATE OR REPLACE FUNCTION json_tree() RETURNS jsonb AS $$
DECLARE
    _json_output jsonb;
    _temprow record;
BEGIN
    SELECT 
        jsonb_build_object('name', name, 'children', array_to_json(ARRAY[]::int[])) 
    INTO _json_output 
    FROM test 
    WHERE parent_node IS NULL;

    FOR _temprow IN
        /* Query above */
    LOOP
        SELECT jsonb_insert(_json_output, _temprow.path, _temprow.json) INTO _json_output;
    END LOOP;

    RETURN _json_output;
END;
$$ LANGUAGE plpgsql;
 

Sidste trin er at kalde funktionen og gøre JSON mere læsbar (jsonb_pretty() )

{ "name": "node1", "children": [{ "name": "node2", "children": [{ "name": "node4", "children": [] }, { "name": "node5", "children": [] }, { "name": "node6", "children": [] }] }, { "name": "node3", "children": [{ "name": "node7", "children": [] }, { "name": "node8", "children": [] }] }] }

Jeg er sikker på, at det er muligt at optimere forespørgslen, men for en skitse virker det.




  1. Få BLOB fra BFILE-kolonnen i Oracle

  2. MySQL ATAN2() Funktion – Returner buetangenten af ​​2 værdier

  3. Sådan får du aktuelle ugedata i MySQL

  4. Databasesikkerhedsovervågning til MySQL og MariaDB