«ERREUR: littéral de tableau mal formé» lors de l'utilisation de json_to_record avec un élément de tableau JSON dans Postgres 9.4

9

Cela illustre bien le problème:

Lorsque la colonne b est de type texte et non un tableau, les opérations suivantes fonctionnent:

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"] |

Mais si je définis la bcolonne comme un tableau, j'obtiens cette erreur:

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.

Comment convaincre / contraindre json_to_record(ou json_populate_record) convertir un tableau JSON en tableau Postgres du type de colonne cible?

Taytay
la source

Réponses:

6

Juste une légère variation de la réponse de Chris:

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);

L'idée est la même: masser le tableau JSON dans un tableau - dans ce cas, à travers un tableau littéral. En plus d'un code un peu plus propre (bien que je l'adore, l'expression régulière n'aide pas beaucoup à cet égard :), elle semble légèrement plus rapide aussi:

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);

Sur ce jeu de données et sur ma boîte de test, la version regex affiche et le temps d'exécution moyen de 300 ms , tandis que ma version affiche 210 ms .

dezso
la source
1

Ce n'est peut-être pas la solution la plus élégante, mais cela résoudra vos problèmes ...

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);

Son fonctionnement est assez simple:

Tout d'abord , prenez la textchaîne bet retirez-la pour obtenir les informations utiles. Cela se fait en utilisant regexp_replace()comme

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

pour supprimer toutes les instances de [, ", ], et tous les caractères blancs, ou plus précisément, pour remplacer toutes les instances de ces caractères avec '', et d'appliquer ce globalement, signalé en utilisant le drapeau 'g'.

Ensuite , divisez simplement la chaîne en un tableau en utilisant string_to_array()comme

string_to_array(your_string,',')

où dans ce cas your_stringest simplement le résultat de ce qui précède regexp_replace(). Le deuxième argument ','indique string_to_array()que les éléments sont séparés par des virgules.

Cela donnera un text[]champ contenant les entrées souhaitées.

Chris
la source