sql >> Databasteknik >  >> RDS >> PostgreSQL

PostgreSQL returnerar resultatet satt som JSON-array?

TL;DR

SELECT json_agg(t) FROM t

för en JSON-array av objekt och

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

för ett JSON-objekt med arrayer.

Lista över objekt

Det här avsnittet beskriver hur man genererar en JSON-array av objekt, där varje rad konverteras till ett enda objekt. Resultatet ser ut så här:

[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]

9.3 och uppåt

json_agg funktionen ger detta resultat direkt. Den räknar automatiskt ut hur den konverterar sin indata till JSON och aggregerar den till en array.

SELECT json_agg(t) FROM t

Det finns ingen jsonb (introducerad i 9.4) version av json_agg . Du kan antingen aggregera raderna till en array och sedan konvertera dem:

SELECT to_jsonb(array_agg(t)) FROM t

eller kombinera json_agg med en skådespelare:

SELECT json_agg(t)::jsonb FROM t

Mina tester tyder på att det går lite snabbare att aggregera dem i en array först. Jag misstänker att detta beror på att casten måste analysera hela JSON-resultatet.

9.2

9.2 har inte json_agg eller to_json funktioner, så du måste använda den äldre array_to_json :

SELECT array_to_json(array_agg(t)) FROM t

Du kan valfritt inkludera en row_to_json ring in frågan:

SELECT array_to_json(array_agg(row_to_json(t))) FROM t

Detta konverterar varje rad till ett JSON-objekt, aggregerar JSON-objekten som en array och konverterar sedan arrayen till en JSON-array.

Jag kunde inte urskilja någon betydande prestandaskillnad mellan de två.

Föremål för listor

Det här avsnittet beskriver hur man genererar ett JSON-objekt, där varje nyckel är en kolumn i tabellen och varje värde är en matris av värdena i kolumnen. Det är resultatet som ser ut så här:

{"a":[1,2,3], "b":["value1","value2","value3"]}

9,5 och uppåt

Vi kan utnyttja json_build_object funktion:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )
FROM t

Du kan också aggregera kolumnerna, skapa en enda rad och sedan konvertera den till ett objekt:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

Observera att aliasing av arrayerna är absolut nödvändigt för att säkerställa att objektet har de önskade namnen.

Vilken som är tydligare är en åsiktsfråga. Om du använder json_build_object funktion rekommenderar jag starkt att du lägger ett nyckel/värdepar på en rad för att förbättra läsbarheten.

Du kan också använda array_agg i stället för json_agg , men mina tester visar att json_agg är något snabbare.

Det finns ingen jsonb version av json_build_object fungera. Du kan slå samman till en enda rad och konvertera:

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

Till skillnad från de andra frågorna för den här typen av resultat, array_agg verkar vara lite snabbare när du använder to_jsonb . Jag misstänker att detta beror på overheadanalys och validering av JSON-resultatet för json_agg .

Eller så kan du använda en explicit rollbesättning:

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )::jsonb
FROM t

to_jsonb versionen låter dig undvika rollbesättningen och är snabbare, enligt mina tester; återigen, jag misstänker att detta beror på overhead för att analysera och validera resultatet.

9.4 och 9.3

json_build_object funktion var ny för 9.5, så du måste aggregera och konvertera till ett objekt i tidigare versioner:

SELECT to_json(r)
FROM (
    SELECT
        json_agg(t.a) AS a,
        json_agg(t.b) AS b
    FROM t
) r

eller

SELECT to_jsonb(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

beroende på om du vill ha json eller jsonb .

(9.3 har inte jsonb .)

9.2

I 9.2, inte ens to_json existerar. Du måste använda row_to_json :

SELECT row_to_json(r)
FROM (
    SELECT
        array_agg(t.a) AS a,
        array_agg(t.b) AS b
    FROM t
) r

Dokumentation

Hitta dokumentationen för JSON-funktionerna i JSON-funktioner.

json_agg finns på sidan för sammanställda funktioner.

Design

Om prestanda är viktigt, se till att du jämför dina frågor mot ditt eget schema och dina egna data, istället för att lita på mina tester.

Om det är en bra design eller inte beror verkligen på din specifika applikation. När det gäller underhållbarhet ser jag inget speciellt problem. Det förenklar din appkod och betyder att det finns mindre att underhålla i den delen av appen. Om PG kan ge dig exakt det resultat du behöver ur lådan, skulle den enda anledningen jag kan komma på att inte använda det vara prestandaöverväganden. Uppfinn inte hjulet igen och allt.

Null

Aggregatfunktioner ger vanligtvis tillbaka NULL när de fungerar över noll rader. Om detta är en möjlighet kanske du vill använda COALESCE att undvika dem. Ett par exempel:

SELECT COALESCE(json_agg(t), '[]'::json) FROM t

Eller

SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t

Tack till Hannes Landeholm för att han påpekade detta



  1. Utmaningslösningar för nummerseriegenerator – del 3

  2. Stöder Oracle fulltextsökning?

  3. Java:Anropar en lagrad procedur i en Oracle-databas

  4. Ansluta Talend på Windows till en ODBC-databas