it-swarm.com.de

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

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 jedoch die Spalte b 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) um ein JSON-Array in das Postgres-Array des Zielspaltentyps zu konvertieren?

9
Taytay

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 0 ms, während meine Version 210 ms anzeigt.

6
dezso

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, nimm die Zeichenfolge text in b und reduziere sie auf die nützlichen Informationen. Dies geschieht mit regexp_replace() as

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

um alle Instanzen von [, ", ] und Leerzeichen zu entfernen oder um alle Instanzen dieser Zeichen durch '' zu ersetzen. und dies global anzuwenden, signalisiert mit dem Flag 'g'.

Weiter, teilen Sie den String einfach mit string_to_array() as in ein Array

string_to_array(your_string,',')

wobei in diesem Fall your_string einfach das Ergebnis der obigen regexp_replace() ist. Das zweite Argument ',' Zeigte string_to_array() an, dass die Elemente durch Kommas getrennt sind.

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

1
Chris