“ERRO: literal de matriz malformada” ao usar json_to_record com um elemento de matriz JSON no Postgres 9.4

9

Isso ilustra bem o problema:

Quando a coluna b é do tipo texto e não uma matriz, o seguinte funciona:

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

Mas se eu definir a bcoluna como uma matriz, recebo este erro:

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.

Como convencer / coagir json_to_record(ou json_populate_record) a converter uma matriz JSON na matriz Postgres do tipo de coluna de destino?

Taytay
fonte

Respostas:

6

Apenas uma ligeira variação da resposta 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);

A idéia é a mesma: massageie o array JSON em um array - nesse caso, através de um literal de array. Além de um código um pouco mais limpo (embora eu o ame, o regex geralmente não ajuda muito nesse sentido :), parece um pouco mais rápido também:

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

Neste conjunto de dados e na minha caixa de teste, a versão regex mostra e o tempo médio de execução de 300 ms , enquanto minha versão mostra 210 ms .

dezso
fonte
1

Esta pode não ser a solução mais elegante, mas solucionará seus problemas ...

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

É bem simples como funciona:

Primeiro , pegue a textcorda be remova -a para obter as informações úteis. Isso é feito usando regexp_replace()como

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

para remover todos os casos de [, ", ], e quaisquer espaços em branco, ou mais especificamente, para substituir quaisquer dos casos esses caracteres com '', e para aplicar esta globalmente, sinalizou usando o sinalizador 'g'.

Em seguida , basta dividir a string em uma matriz usando string_to_array()como

string_to_array(your_string,',')

onde, neste caso, your_stringé simplesmente o resultado do exposto acima regexp_replace(). O segundo argumento ','indicava string_to_array()que os itens são separados por vírgula.

Isso produzirá um text[]campo contendo as entradas desejadas.

Chris
fonte