在Postgres 9.4中将json_to_record与JSON数组元素一起使用时出现“错误:格式错误的数组文字”


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数组?

Answers:


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 ms,而我的版本显示210 ms


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()as 完成的

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

以除去的所有实例["],和任何空白字符,或更具体地,替换这些字符用的任何实例'',并且通过使用该标志来应用此全球范围内,发信号通知'g'

接下来,只需使用string_to_array()as 将字符串拆分为一个数组

string_to_array(your_string,',')

在这种情况下your_string,仅仅是上述结果regexp_replace()。第二个参数','表明string_to_array()项目以逗号分隔。

这将产生一个text[]包含所需条目的字段。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.