"ERRORE: letterale di matrice non valido" quando si utilizza json_to_record con un elemento di matrice JSON in Postgres 9.4


9

Questo illustra bene il problema:

Quando la colonna b è di tipo testo e non un array, funziona come segue:

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

Ma se definisco la bcolonna come un array, ottengo questo errore:

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.

Come posso convincere / forzare json_to_record(o json_populate_record) a convertire un array JSON nell'array Postgres del tipo di colonna di destinazione?

Risposte:


6

Solo una leggera variazione alla risposta di 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'idea è la stessa: massaggiare l'array JSON in un array - in questo caso, attraverso un array letterale. Oltre a un codice un po 'più pulito (anche se lo adoro, regex di solito non aiuta molto in questo senso :), sembra anche leggermente più veloce:

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

Su questo set di dati e sulla mia casella di test, la versione regex mostra e il tempo medio di esecuzione di 300 ms , mentre la mia versione mostra 210 ms .


1

Questa potrebbe non essere la soluzione più elegante, ma risolverà i tuoi problemi ...

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

È abbastanza semplice come funziona:

Innanzitutto , prendi la textstringa be spoglila fino alle informazioni utili. Questo viene fatto usando regexp_replace()as

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

per rimuovere tutte le istanze [, ", ], e qualsiasi carattere di spazio bianco, o più specificamente, per sostituire le istanze di questi caratteri con '', e di applicare il presente globalmente, segnalata utilizzando il flag 'g'.

Quindi , dividi semplicemente la stringa in un array usando string_to_array()as

string_to_array(your_string,',')

dove in questo caso your_stringè semplicemente il risultato di quanto sopra regexp_replace(). Il secondo argomento ','indicava string_to_array()che gli elementi sono separati da virgola.

Questo produrrà un text[]campo contenente le voci desiderate.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.