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 colonne b
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 puis-je convaincre/contraindre json_to_record
(ou json_populate_record
) pour convertir un tableau JSON en tableau Postgres du type de colonne cible?
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'aime, 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 cet ensemble de données et sur ma boîte de test, la version regex affiche et le temps d'exécution moyen de 0 ms, tandis que ma version affiche 210 ms.
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:
First, prenez la chaîne text
dans b
, et supprimez-la aux informations utiles. Cela se fait en utilisant regexp_replace()
as
regexp_replace(b, '\[*\"*\s*\]*','','g')
pour supprimer toutes les instances de [
, "
, ]
et tous les espaces, ou plus précisément, pour remplacer toute instance de ces caractères par ''
, et pour l'appliquer globalement, signalé par l'utilisation de l'indicateur 'g'
.
Next, divisez simplement la chaîne en un tableau en utilisant string_to_array()
as
string_to_array(your_string,',')
où dans ce cas your_string
est simplement le résultat de la regexp_replace()
ci-dessus. Le deuxième argument ','
A indiqué à string_to_array()
que les éléments sont séparés par des virgules.
Cela produira un champ text[]
Contenant les entrées souhaitées.