"FEHLER: fehlerhaftes Array-Literal" bei Verwendung von json_to_record mit einem JSON-Array-Element in Postgres 9.4

9

Dies veranschaulicht das Problem gut:

Wenn Spalte b vom Typ Text und kein Array ist, funktioniert Folgendes:

select * 
from json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}') 
    as x(a int, b text, d text);

 a |         b          | d
---+--------------------+---
 1 | ["hello", "There"] |

Wenn ich die bSpalte jedoch als Array definiere, wird folgende Fehlermeldung angezeigt:

select * 
from json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}') 
    as x(a int, b text[], d text)

ERROR:  malformed array literal: "["hello", "There"]"
DETAIL:  "[" must introduce explicitly-specified array dimensions.

Wie kann ich überzeugen / zwingen json_to_record(oder json_populate_record), ein JSON-Array in das Postgres-Array des Zielspaltentyps zu konvertieren?

Taytay
quelle

Antworten:

6

Nur eine kleine Variation von Chris 'Antwort:

SELECT a, translate(b, '[]', '{}')::text[] AS b, d
FROM json_to_record('{"a": 1, "b": ["hello", "There"], "c": "bar"}')
AS x(a int, b text, d text);

Die Idee ist dieselbe: Massieren Sie das JSON-Array in ein Array - in diesem Fall durch ein Array-Literal. Zusätzlich zu einem etwas sauberer aussehenden Code (obwohl ich ihn liebe, hilft Regex in dieser Hinsicht normalerweise nicht viel :), scheint er auch etwas schneller zu sein:

CREATE TABLE jsonb_test (
    id serial,
    data jsonb
);

INSERT INTO jsonb_test (id, data)
SELECT i, format('{"a": %s, "b": ["foo", "bar"], "c": "baz"}', i::text)::jsonb 
FROM generate_series(1,10000) t(i);

SELECT a, string_to_array(regexp_replace(b, '\[*\"*\s*\]*','','g'),',') AS b, d
FROM jsonb_test AS j, 
LATERAL json_to_record(j.data::json) AS r(a int, b text, d text);

-- versus 

SELECT a, translate(b, '[]', '{}')::text[] AS b, d
FROM jsonb_test AS j, 
LATERAL json_to_record(j.data::json) AS r(a int, b text, d text);

In diesem Datensatz und in meiner Testbox zeigt die Regex-Version eine durchschnittliche Ausführungszeit von 300 ms , während meine Version 210 ms anzeigt .

dezso
quelle
1

Dies ist vielleicht nicht die eleganteste Lösung, aber es wird Ihre Probleme beheben ...

SELECT a,string_to_array(regexp_replace(b, '\[*\"*\s*\]*','','g'),',') AS b,d
FROM json_to_record('{"a":1,"b":["hello", "There"],"c":"bar"}')
AS x(a int, b text, d text);

Es ist ziemlich einfach, wie es funktioniert:

Zuerst nehmen Sie die textZeichenfolge in b, und die Streifen an den nützlichen Informationen nach unten. Dies erfolgt mit regexp_replace()as

regexp_replace(b, '\[*\"*\s*\]*','','g')

alle Instanzen zu entfernen [, ", ]und alle Leerzeichen, oder genauer gesagt, um alle Instanzen dieser Zeichen zu ersetzen '', und dies global anwenden, unter Verwendung der Flagge signalisiert 'g'.

Teilen Sie als Nächstes einfach die Zeichenfolge mit string_to_array()as in ein Array auf

string_to_array(your_string,',')

wo in diesem Fall your_stringist einfach das Ergebnis der oben genannten regexp_replace(). Das zweite Argument ','deutete darauf hin, string_to_array()dass die Elemente durch Kommas getrennt sind.

Dies ergibt ein text[]Feld mit Ihren gewünschten Einträgen.

Chris
quelle