2017-02-14 3 views
3

Ich muss als Ergebnis von Abfrage vollständig strukturierten JSON erhalten. Ich kann in Postgres sehen, dass es einige eingebaute Funktionen gibt, die nützlich sein können.Erstellen Sie verschachtelte JSON von SQL-Abfrage Postgres 9.4

Als Beispiel habe ich eine Struktur wie folgt:

-- Table: person 

-- DROP TABLE person; 

CREATE TABLE person 
(
    id integer NOT NULL, 
    name character varying(30), 
    CONSTRAINT person_pk PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE person 
    OWNER TO postgres; 

    -- Table: car 

-- DROP TABLE car; 

CREATE TABLE car 
(
    id integer NOT NULL, 
    type character varying(30), 
    personid integer, 
    CONSTRAINT car_pk PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE car 
    OWNER TO postgres; 

    -- Table: wheel 

-- DROP TABLE wheel; 

CREATE TABLE wheel 
(
    id integer NOT NULL, 
    whichone character varying(30), 
    serialnumber integer, 
    carid integer, 
    CONSTRAINT "Wheel_PK" PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE wheel 
    OWNER TO postgres; 

und einige Daten:

INSERT INTO person(id, name) 
VALUES (1, 'Johny'), 
     (2, 'Freddy'); 

INSERT INTO car(id, type, personid) 
VALUES (1, 'Toyota', 1), 
     (2, 'Fiat', 1),  
     (3, 'Opel', 2);  

INSERT INTO wheel(id, whichone, serialnumber, carid) 
VALUES (1, 'front', '11', 1), 
     (2, 'back', '12', 1), 
     (3, 'front', '21', 2), 
     (4, 'back', '22', 2), 
     (5, 'front', '3', 3); 

Als Ergebnis Ich mag würde ein JSON-Objekt haben, die Liste der Personen enthalten würde, Jede Person wird eine Liste von Autos und jede Auto-Liste von Rädern haben.

habe ich versucht, so etwas, aber es ist nicht etwas, das ich will:

select json_build_object(
    'Persons', json_build_object(
    'person_name', person.name, 
    'cars', json_build_object(
     'carid', car.id,  
     'type', car.type, 
     'comment', 'nice car', -- this is constant 
     'wheels', json_build_object(
      'which', wheel.whichone, 
      'serial number', wheel.serialnumber 
     ) 

    )) 
) 

from 
person 
left join car on car.personid = person.id 
left join wheel on wheel.carid = car.id 

Ich nehme an, dass ich eine Gruppe von und json_agg bin fehlt, aber ich bin nicht sicher, wie dies zu tun.

Ich mag als ein Ergebnis, so etwas haben:

{ "persons": [ 
    { 
     "person_name": "Johny", 
     "cars": [ 
      { 
      "carid": 1, 
      "type": "Toyota", 
      "comment": "nice car", 
      "wheels": [{ 
       "which": "Front", 
       "serial number": 11 
      }, 
      { 
       "which": "Back", 
       "serial number": 12 
      }] 
      }, 
      { 
      "carid": 2, 
      "type": "Fiat", 
      "comment": "nice car", 
      "wheels": [{ 
       "which": "Front", 
       "serial number": 21 
      },{ 
       "which": "Back", 
       "serial number": 22 
      }] 
      } 
     ] 
    }, 
    { 
     "person_name": "Freddy", 
     "cars": [ 
      { 
      "carid": 3, 
      "type": "Opel", 
      "comment": "nice car", 
      "wheels": [{ 
       "which": "Front", 
       "serial number": 33 
      }] 
      }] 
    }] 
} 

http://www.jsoneditoronline.org/?id=7792a0a2bf11be724c29bb86c4b14577

+0

@a_horse_with_no_name – Snorlax

Antwort

3

Sie eine hierarchische Abfrage aufbauen sollte eine hierarchische Struktur als Ergebnis zu erhalten.

Sie möchten viele Personen in einem einzelnen JSON-Objekt haben, verwenden Sie also json_agg(), um Personen in einem JSON-Array zu sammeln. Analog kann eine Person mehrere Autos haben und Sie sollten Autos einer einzelnen Person in einem JSON-Array platzieren. Gleiches gilt für Autos und Räder.

select 
    json_build_object(
     'persons', json_agg(
      json_build_object(
       'person_name', p.name, 
       'cars', cars 
      ) 
     ) 
    ) persons 
from person p 
left join (
    select 
     personid, 
     json_agg(
      json_build_object(
       'carid', c.id,  
       'type', c.type, 
       'comment', 'nice car', -- this is constant 
       'wheels', wheels 
       ) 
      ) cars 
    from 
     car c 
     left join (
      select 
       carid, 
       json_agg(
        json_build_object(
         'which', w.whichone, 
         'serial number', w.serialnumber 
        ) 
       ) wheels 
      from wheel w 
      group by 1 
     ) w on c.id = w.carid 
    group by personid 
) c on p.id = c.personid; 

Die (formatiert) Ergebnis:

{ 
    "persons": [ 
     { 
      "person_name": "Johny", 
      "cars": [ 
       { 
        "carid": 1, 
        "type": "Toyota", 
        "comment": "nice car", 
        "wheels": [ 
         { 
          "which": "front", 
          "serial number": 11 
         }, 
         { 
          "which": "back", 
          "serial number": 12 
         } 
        ] 
       }, 
       { 
        "carid": 2, 
        "type": "Fiat", 
        "comment": "nice car", 
        "wheels": [ 
         { 
          "which": "front", 
          "serial number": 21 
         }, 
         { 
          "which": "back", 
          "serial number": 22 
         } 
        ] 
       } 
      ] 
     }, 
     { 
      "person_name": "Freddy", 
      "cars": [ 
       { 
        "carid": 3, 
        "type": "Opel", 
        "comment": "nice car", 
        "wheels": [ 
         { 
          "which": "front", 
          "serial number": 3 
         } 
        ] 
       } 
      ] 
     } 
    ] 
} 

Wenn Sie nicht vertraut mit verschachtelten abgeleiteten Tabellen sind, können Sie allgemeine Tabellenausdrücke verwenden. Diese Variante zeigt, dass die Abfrage ausgehend von dem am meisten verschachtelten Objekt in Richtung der höchsten Ebene gebaut werden soll:

with wheels as (
    select 
     carid, 
     json_agg(
      json_build_object(
       'which', w.whichone, 
       'serial number', w.serialnumber 
      ) 
     ) wheels 
    from wheel w 
    group by 1 
), 
cars as (
    select 
     personid, 
     json_agg(
      json_build_object(
       'carid', c.id,  
       'type', c.type, 
       'comment', 'nice car', -- this is constant 
       'wheels', wheels 
       ) 
      ) cars 
    from car c 
    left join wheels w on c.id = w.carid 
    group by c.personid 
) 
select 
    json_build_object(
     'persons', json_agg(
      json_build_object(
       'person_name', p.name, 
       'cars', cars 
      ) 
     ) 
    ) persons 
from person p 
left join cars c on p.id = c.personid; 
+0

getan und was zu tun ist, wenn ich Ergebnisse begrenzen nur von db ersten 10 Personen möchten? – Snorlax

+1

Sie sollten 'person' durch eine abgeleitete Tabelle ersetzen, d. H. Anstelle von' from person p' use' from (wählen Sie * from person ... limit 10) p'. – klin

+0

Perfekt! Und noch eine Sache, wha, wenn ich sicher bin, dass alle Person nur ein Auto haben und ich nicht Array von Objekten aber Objekt in den Resultaten json anzeigen möchte? Wie man es leicht ändert? – Snorlax

3

ich mit dieser Lösung zu kommen habe. Es ist ziemlich kompakt und funktioniert in jedem Fall. Nicht sicher, aber was ist die Auswirkung auf die Leistung im Vergleich zu anderen Lösungen, die mehr nutzen json_build_object. Der Vorteil der Verwendung row_to_json über json_build_object ist, dass die ganze Arbeit unter der Haube erfolgt, die die Abfrage lesbarer macht.

SELECT json_build_object('persons', json_agg(p)) persons 
FROM (
     SELECT 
     person.name person_name, 
     (
      SELECT json_agg(row_to_json(c)) 
      FROM (
        SELECT 
        id carid, 
        type, 
        (
         SELECT json_agg(row_to_json(w)) 
         FROM (
          SELECT 
           whichone which, 
           serialnumber 
          FROM wheel 
          WHERE wheel.carid = car.id 
          ) w 
        ) wheels 
        FROM car 
        WHERE car.personid = person.id 
       ) c 
     ) AS  cars 
     FROM person 
) p 
+0

Ok und lassen Sie uns sagen, dass zusätzlich Auto 0 oder 1 Motor haben kann. Wie verschachteln Sie es als Objekt, nicht als Array von Objekten? – Snorlax

+1

Dann fügen Sie einfach die Engine neben den Rädern in einem Subselect hinzu und transformieren Sie sie in json mit der Funktion to_json. SELECT json_build_object ('Personen', json_agg (p)) Personen FROM (SELECT Person.name Person_Name, (SELECT json_agg (row_to_json (c)) FROM (SELECT ID Carid, Typ, (SELECT to_json (e) FROM (SELECT Pferd PS von Motor wo engine.carid = car.id) e) Motor, (SELECT json_agg (row_to_json (w)) FROM (SELECT whichone, Seriennummer FROM Rad WHERE rad.carid = car.id) w) Räder von Auto WO car.personalid = Person .id) c) AS-Autos VON Person) p –

Verwandte Themen