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

PostgreSQL returnerer resultatet sat som JSON-array?

TL;DR

SELECT json_agg(t) FROM t
 

for en JSON-array af objekter og

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

for et JSON-objekt af arrays.

Liste over objekter

Dette afsnit beskriver, hvordan man genererer et JSON-array af objekter, hvor hver række konverteres til et enkelt objekt. Resultatet ser således ud:

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

9.3 og op

json_agg funktion producerer dette resultat ud af boksen. Den finder automatisk ud af, hvordan dens input konverteres til JSON og samler den til et array.

SELECT json_agg(t) FROM t
 

Der er ingen jsonb (introduceret i 9.4) version af json_agg . Du kan enten aggregere rækkerne til en matrix og derefter konvertere dem:

SELECT to_jsonb(array_agg(t)) FROM t
 

eller kombiner json_agg med en rollebesætning:

SELECT json_agg(t)::jsonb FROM t
 

Min test tyder på, at det først er lidt hurtigere at samle dem i et array. Jeg formoder, at dette skyldes, at castet skal analysere hele JSON-resultatet.

9,2

9.2 har ikke json_agg eller to_json funktioner, så du skal bruge den ældre array_to_json :

SELECT array_to_json(array_agg(t)) FROM t
 

Du kan eventuelt inkludere en row_to_json ring ind forespørgslen:

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

Dette konverterer hver række til et JSON-objekt, samler JSON-objekterne som et array og konverterer derefter arrayet til et JSON-array.

Jeg var ikke i stand til at skelne nogen væsentlig forskel i ydeevnen mellem de to.

Objekt med lister

Dette afsnit beskriver, hvordan man genererer et JSON-objekt, hvor hver nøgle er en kolonne i tabellen, og hver værdi er en matrix af værdierne i kolonnen. Det er resultatet, der ser sådan ud:

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

9,5 og op

Vi kan udnytte json_build_object funktion:

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

Du kan også samle kolonnerne, oprette en enkelt række og derefter konvertere den til et objekt:

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

Bemærk, at aliasing af arrays er absolut nødvendig for at sikre, at objektet har de ønskede navne.

Hvilken en der er tydeligst er et spørgsmål om mening. Hvis du bruger json_build_object funktion, anbefaler jeg stærkt at sætte ét nøgle/værdi-par på en linje for at forbedre læsbarheden.

Du kan også bruge array_agg i stedet for json_agg , men min test viser, at json_agg er lidt hurtigere.

Der er ingen jsonb version af json_build_object fungere. Du kan samle til en enkelt række og konvertere:

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

I modsætning til de andre forespørgsler for denne slags resultater, array_agg ser ud til at være lidt hurtigere, når du bruger to_jsonb . Jeg formoder, at dette skyldes overhead-parsing og validering af JSON-resultatet af json_agg .

Eller du kan bruge en eksplicit rollebesætning:

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

to_jsonb version giver dig mulighed for at undgå rollebesætningen og er hurtigere, ifølge min test; igen, jeg formoder, at dette skyldes overhead ved parsing og validering af resultatet.

9.4 og 9.3

json_build_object funktion var ny i 9.5, så du skal aggregere og konvertere til et objekt i tidligere 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
 

afhængig af om du vil have json eller jsonb .

(9.3 har ikke jsonb .)

9,2

I 9.2, ikke engang to_json eksisterer. Du skal bruge 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

Find dokumentationen til JSON-funktionerne i JSON-funktioner.

json_agg er på siden for samlede funktioner.

Design

Hvis ydeevne er vigtig, skal du sikre dig, at du benchmarker dine forespørgsler mod dit eget skema og dine data i stedet for at stole på min test.

Om det er et godt design eller ej, afhænger virkelig af din specifikke anvendelse. Med hensyn til vedligeholdelse ser jeg ikke noget særligt problem. Det forenkler din app-kode og betyder, at der er mindre at vedligeholde i den del af appen. Hvis PG kan give dig præcis det resultat, du har brug for ud af boksen, er den eneste grund, jeg kan komme i tanke om til ikke at bruge det, ydelsesovervejelser. Lad være med at genopfinde hjulet og det hele.

Nuller

Aggregerede funktioner giver typisk NULL tilbage når de kører over nul rækker. Hvis dette er en mulighed, vil du måske bruge COALESCE at undgå dem. Et par eksempler:

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

Eller

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

Til ære til Hannes Landeholm for at påpege dette



  1. 12.2 RAC/GI Nye funktioner

  2. 3 måder at returnere en streng af flere mellemrum i SQL Server

  3. mysql_fetch_array returnerer kun én række

  4. Hvordan forespørger man værdier fra xml-noder?