TL; DR
SELECT json_agg(t) FROM t
für ein JSON-Array von Objekten und
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
für ein JSON-Objekt von Arrays.
Liste der Objekte
In diesem Abschnitt wird beschrieben, wie Sie ein JSON-Array von Objekten generieren, wobei jede Zeile in ein einzelnes Objekt konvertiert wird. Das Ergebnis sieht folgendermaßen aus:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 und höher
Die json_agg
Funktion erzeugt dieses Ergebnis sofort. Es findet automatisch heraus, wie seine Eingabe in JSON konvertiert und zu einem Array zusammengefasst wird.
SELECT json_agg(t) FROM t
Es gibt keine jsonb
(in 9.4 eingeführte) Version von json_agg
. Sie können die Zeilen entweder zu einem Array zusammenfassen und dann konvertieren:
SELECT to_jsonb(array_agg(t)) FROM t
oder json_agg
mit einer Besetzung kombinieren :
SELECT json_agg(t)::jsonb FROM t
Meine Tests legen nahe, dass die Aggregation zu einem Array etwas schneller ist. Ich vermute, dass dies daran liegt, dass die Besetzung das gesamte JSON-Ergebnis analysieren muss.
9.2
9.2 verfügt nicht über die Funktionen json_agg
oder to_json
, daher müssen Sie die älteren verwenden array_to_json
:
SELECT array_to_json(array_agg(t)) FROM t
Sie können optional einen row_to_json
Anruf in die Abfrage aufnehmen:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Dadurch wird jede Zeile in ein JSON-Objekt konvertiert, die JSON-Objekte werden als Array zusammengefasst und anschließend wird das Array in ein JSON-Array konvertiert.
Ich konnte keinen signifikanten Leistungsunterschied zwischen den beiden feststellen.
Objekt von Listen
In diesem Abschnitt wird beschrieben, wie Sie ein JSON-Objekt generieren, wobei jeder Schlüssel eine Spalte in der Tabelle und jeder Wert ein Array der Werte der Spalte ist. Das Ergebnis sieht folgendermaßen aus:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9,5 und höher
Wir können die json_build_object
Funktion nutzen:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Sie können die Spalten auch aggregieren, eine einzelne Zeile erstellen und diese dann in ein Objekt konvertieren:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Beachten Sie, dass ein Aliasing der Arrays unbedingt erforderlich ist, um sicherzustellen, dass das Objekt die gewünschten Namen hat.
Welches klarer ist, ist Ansichtssache. Wenn Sie die json_build_object
Funktion verwenden, empfehle ich dringend, ein Schlüssel / Wert-Paar in eine Zeile zu setzen, um die Lesbarkeit zu verbessern.
Sie könnten auch array_agg
anstelle von verwenden json_agg
, aber meine Tests zeigen, dass json_agg
das etwas schneller ist.
Es gibt keine jsonb
Version der json_build_object
Funktion. Sie können zu einer einzelnen Zeile zusammenfassen und Folgendes konvertieren:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Im Gegensatz zu den anderen Abfragen für diese Art von Ergebnis array_agg
scheint die Verwendung etwas schneller zu sein to_jsonb
. Ich vermute, dass dies auf das Overhead-Parsen und Validieren des JSON-Ergebnisses von zurückzuführen ist json_agg
.
Oder Sie können eine explizite Besetzung verwenden:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
Die to_jsonb
Version ermöglicht es Ihnen, die Besetzung zu vermeiden und ist laut meinen Tests schneller; Ich vermute erneut, dass dies auf den Aufwand für das Parsen und Validieren des Ergebnisses zurückzuführen ist.
9.4 und 9.3
Die json_build_object
Funktion war neu in 9.5, daher müssen Sie in früheren Versionen aggregieren und in ein Objekt konvertieren:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
oder
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
je nachdem ob du willst json
oder jsonb
.
(9.3 hat nicht jsonb
.)
9.2
In 9.2 existiert nicht einmal to_json
. Sie müssen verwenden 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
Die Dokumentation zu den JSON-Funktionen finden Sie unter JSON-Funktionen .
json_agg
befindet sich auf der Seite mit den Aggregatfunktionen .
Design
Wenn die Leistung wichtig ist, stellen Sie sicher, dass Sie Ihre Abfragen mit Ihrem eigenen Schema und Ihren eigenen Daten vergleichen, anstatt meinen Tests zu vertrauen.
Ob es sich um ein gutes Design handelt oder nicht, hängt wirklich von Ihrer spezifischen Anwendung ab. In Bezug auf die Wartbarkeit sehe ich kein besonderes Problem. Dies vereinfacht Ihren App-Code und bedeutet, dass in diesem Teil der App weniger zu warten ist. Wenn PG Ihnen genau das Ergebnis liefern kann, das Sie sofort benötigen, ist der einzige Grund, warum ich mir vorstellen kann, es nicht zu verwenden, Leistungsüberlegungen. Das Rad und alles nicht neu erfinden.
Nullen
Aggregatfunktionen geben normalerweise etwas zurück, NULL
wenn sie über Nullzeilen arbeiten. Wenn dies eine Möglichkeit ist, möchten Sie sie möglicherweise COALESCE
vermeiden. Einige Beispiele:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Oder
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Dank an Hannes Landeholm für diesen Hinweis