"ПОМИЛКА: неправильно сформований масив літералу" при використанні json_to_record з елементом масиву JSON в Postgres 9.4


9

Це добре ілюструє проблему:

Коли стовпець b є текстовим типом, а не масивом, працює наступне:

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

Але якщо я визначаю bстовпець як масив, я отримую цю помилку:

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.

Як я можу переконати / примусити json_to_record(чи json_populate_record) перетворити масив JSON у масив Postgres цільового типу стовпця?

Відповіді:


6

Лише незначна зміна відповіді Кріса:

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

Ідея та ж: масажуйте масив JSON в масив - в цьому випадку через літерал масиву. На додаток до трохи більш чистого вигляду коду (хоча мені це подобається, регулярно генекс не дуже допомагає в цьому плані :), але це здається трохи швидшим:

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

На цьому наборі даних і в моєму тестовому вікні відображається версія регулярного виразів і середній час виконання 300 мс , тоді як моя версія показує 210 мс .


1

Це може бути не найелегантнішим рішенням, але воно вирішить ваші проблеми ...

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

Це досить просто, як це працює:

Спочатку візьміть textрядок bі закресліть її до корисної інформації. Це робиться за допомогою regexp_replace()як

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

щоб видалити всі екземпляри [, ", ], і будь-які пробільні символи, або , більш конкретно, замінити всі екземпляри цих символів з '', і застосовувати це в глобальному масштабі, сигнализируется за допомогою прапора 'g'.

Далі просто розділіть рядок на масив, використовуючи string_to_array()як

string_to_array(your_string,',')

де в цьому випадку your_stringпросто результат вищезазначеного regexp_replace(). Другий аргумент ','вказував на string_to_array()те, що елементи розділені комами.

Це дозволить отримати text[]поле, що містить бажані записи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.