Ich habe eine Spalte data
, die ein json
Dokument ungefähr so enthält:
{
"name": "foo",
"tags": ["foo", "bar"]
}
Ich möchte das verschachtelte tags
Array in eine verkettete Zeichenfolge ( foo, bar
) verwandeln . Das wäre mit der array_to_string()
Funktion in der Theorie leicht möglich . Diese Funktion wirkt sich jedoch nicht auf json
Arrays aus. Also frage ich mich, wie ich dieses json
Array in ein Postgres verwandeln kann array
?
postgresql
postgresql-9.3
array
json
Christoph
quelle
quelle
json_extract_path_text(your_column, 'tags')
was du suchstAntworten:
Postgres 9.4 oder neuer
Postgres 9.4 wurde offensichtlich von diesem Beitrag inspiriert und fügte die fehlenden Funktionen hinzu:
Danke an Laurence Rowe für den Patch und Andrew Dunstan für das Commit!
json_array_elements_text(json)
jsonb_array_elements_text(jsonb)
So entfernen Sie das JSON-Array. Verwenden Sie dann
array_agg()
oder einen ARRAY-Konstruktor , um ein Postgres- Array daraus zu erstellen . Oderstring_agg()
um einentext
String zu bauen .Aggregieren Sie nicht verschachtelte Elemente pro Zeile in einer
LATERAL
oder einer korrelierten Unterabfrage. Dann wird ursprünglicher Auftrag erhalten und wir nicht brauchenORDER BY
,GROUP BY
oder sogar ein eindeutiger Schlüssel in der äußeren Abfrage. Sehen:Ersetzen Sie 'json'
jsonb
in allen folgenden SQL-Codes durch 'jsonb' .Kurze Syntax:
Verbunden:
ARRAY-Konstruktor in korrelierter Unterabfrage:
Verbunden:
Subtiler Unterschied :
null
Elemente bleiben in tatsächlichen Arrays erhalten . Dies ist in den obigen Abfragen, die einetext
Zeichenfolge erzeugen , die keinenull
Werte enthalten kann, nicht möglich . Die wahre Darstellung ist ein Array.Funktions-Wrapper
Um dies noch einfacher zu machen, kapseln Sie bei wiederholter Verwendung die Logik in eine Funktion:
Machen Sie es zu einer SQL-Funktion , damit es in größeren Abfragen eingebunden werden kann.
Machen Sie es
IMMUTABLE
(weil es ist), um wiederholte Auswertung in größeren Abfragen zu vermeiden und es in Indexausdrücken zuzulassen.Anruf:
db <> hier fummeln
Postgres 9.3 oder älter
Nutzen Sie die Funktion
json_array_elements()
. Aber wir bekommen doppelte Anführungszeichen .Alternative Abfrage mit Aggregation in der äußeren Abfrage.
CROSS JOIN
Entfernt Zeilen mit fehlenden oder leeren Arrays. Kann auch zur Verarbeitung von Elementen nützlich sein. Wir benötigen einen eindeutigen Schlüssel für die Aggregation:ARRAY-Konstruktor, immer noch mit zitierten Zeichenfolgen:
Beachten Sie, dass
null
im Gegensatz zu oben in den Textwert "null" konvertiert wird. Falsch, genau genommen und möglicherweise mehrdeutig.Der arme Mann spricht nicht mit
trim()
:Rufen Sie eine einzelne Zeile von tbl ab:
Zeichenfolgen bilden eine korrelierte Unterabfrage:
ARRAY-Konstruktor:
Ursprüngliche (veraltete) SQL-Geige .
db <> hier fummeln .
Verbunden:
Anmerkungen (veraltet seit Seite 9.4)
Wir benötigen a
json_array_elements_text(json)
, den Zwilling vonjson_array_elements(json)
, um korrektetext
Werte aus einem JSON-Array zurückzugeben. Dies scheint jedoch im bereitgestellten Arsenal von JSON-Funktionen zu fehlen . Oder eine andere Funktion, um einentext
Wert aus einem Skalarwert zu extrahierenJSON
. Das scheint mir auch zu fehlen.Also habe ich mit improvisiert
trim()
, aber das wird für nicht-triviale Fälle scheitern ...quelle
to_jsonb()
für die Array-> Jsonb-Konvertierung verwenden.SELECT ARRAY(SELECT json_array_elements_text(_js))
wirklich gewährleistet, dass die Reihenfolge des Arrays erhalten bleibt? Darf der Optimierer nicht theoretisch die Reihenfolge der Zeilen ändern, die aus json_array_elements_text stammen?PG 9.4+
Die akzeptierte Antwort ist definitiv das, was Sie brauchen, aber der Einfachheit halber hier ist ein Helfer, den ich dafür benutze:
Dann machen Sie einfach:
quelle
Diese Frage wurde in den PostgreSQL-Mailinglisten gestellt und ich fand diese hackige Methode zum Konvertieren von JSON-Text in PostgreSQL-Text über den JSON-Feldextraktionsoperator:
Grundsätzlich konvertiert es den Wert in ein Einzelelement-Array und fragt dann nach dem ersten Element.
Ein anderer Ansatz wäre, diesen Operator zu verwenden, um alle Felder einzeln zu extrahieren. Bei großen Arrays ist dies wahrscheinlich langsamer, da der gesamte JSON-String für jedes Array-Element analysiert werden muss, was zu einer Komplexität von O (n ^ 2) führt.
quelle
Ich habe ein paar Optionen getestet. Hier ist meine Lieblingsfrage. Angenommen, wir haben eine Tabelle mit ID und JSON-Feld. Das json-Feld enthält array, das wir in pg array umwandeln wollen.
Es funktioniert überall und ist schneller als andere, sieht aber mürrisch aus.)
Zuerst wird das JSON-Array als Text umgewandelt, und dann ändern wir die eckigen Klammern in Klammern. Schließlich wird der Text als Array des erforderlichen Typs umgewandelt.
und wenn Sie Text [] Arrays bevorzugen
quelle
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
Ich denke, Sie müssen eine Erklärung hinzufügen, wie dies funktionieren soll.SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
Es ist nicht so bombensicher ...Diese wenigen Funktionen, die den Antworten auf diese Frage entnommen sind, werden von mir verwendet und funktionieren hervorragend
In jedem von ihnen wird durch die Verkettung mit einem leeren Array ein Fall behandelt, bei dem ich mir ein wenig den Kopf zerbrochen habe. Wenn Sie versuchen, ein leeres Array von
json
/jsonb
ohne Array zu werfen , wird statt eines nichts zurückgegeben leeres Array ({}
), wie Sie es erwarten würden. Ich bin mir sicher, dass es Optimierungen für sie gibt, aber sie bleiben der Einfachheit halber bei der Erläuterung des Konzepts erhalten.quelle