在postgres中,有一种简单的方法可以在一条记录中选择几个attr / val行吗?

时间:2012-08-05 04:29:53

标签: sql postgresql

如果我有

create table t1( attr text primary key, val text );
insert into t1 values( 'attr1', 'val1' );
insert into t1 values( 'attr2', 'val3' );
insert into t1 values( 'attr3', 'val3' );

希望select返回一行

attr1=>val1, attr2=>val2, attr3=>val3

现在正在javascript中进行转换,但pg返回行本身会很好


答案

根据@ mu的回答,查询:

select replace( replace( replace( array_agg( hstore( attr, val ) )::text
   '"\"', '"'), 
   '\""', '"'),
   '\"=>\"', '":"')  from t1;

结果:

{"attr1":"val1","attr2":val2","attr3":"val3"}

这是非常好的JSON(只要值中没有引号)

2 个答案:

答案 0 :(得分:3)

我希望可以将array_to_jsonarray_agg一起使用。请参阅PostgreSQL 9.2 json documentation了解用法,以及json91模块,该模块支持在PostgreSQL 9.1中使用JSON功能,直到9.2用完,或使用9.2 beta。

不幸的是,事实证明此时似乎没有任何合并,聚合等json的支持。这使得构建JSON值非常困难。我只是使用常规文本操作符来完成它,但这不允许引用问题。

regress=# SELECT '{'||string_agg('"'||attr||'": "'||val||'"', ', ')||'}' FROM t1;
                      ?column?                       
-----------------------------------------------------
 {"attr1": "val1", "attr2": "val3", "attr3": "val3"}
(1 row)

请参阅:

regress=# insert into t1 (attr,val) values ('at"tr', 'v"a"l');
INSERT 0 1
regress=# SELECT '{'||string_agg('"'||attr||'": "'||val||'"', ', ')||'}' FROM t1;
                               ?column?                                
-----------------------------------------------------------------------
 {"attr1": "val1", "attr2": "val3", "attr3": "val3", "at"tr": "v"a"l"}
(1 row)

regress=# SELECT ('{'||string_agg('"'||attr||'": "'||val||'"', ', ')||'}')::json FROM t1;
ERROR:  invalid input syntax for type json
DETAIL:  line 1: Token "tr" is invalid.

您在答案中添加的解决方案中存在同样的问题。为了得到一个好的答案,我们需要类似json_escape_literal的函数,并且目前没有任何类似于SQL的函数。

我在Pg的当前json功能集中看到的唯一安全方法是生成一对数组,但这并不比普通的面向行的查询更好。

regress=# SELECT  array_to_json( array_agg( array_to_json( ARRAY[attr, val] ) )) FROM t1;
                               array_to_json                               
---------------------------------------------------------------------------
 [["attr1","val1"],["attr2","val3"],["attr3","val3"],["at\"tr","v\"a\"l"]]

你可以把hstore和json结合起来做你想做的事情,但那是进入扩展汤。这真正需要的是一个json对象构造函数,它相当于hstore(text[],text[])所以你可以做json相当于:

select hstore( array_agg(attr), array_agg(val) ) from t1;

更新pgsql-general mailing list post on this topic

答案 1 :(得分:1)

如果您安装了hstore,则可以使用array_agg

select array_agg(attr => val) from t1;

这将为您提供您正在寻找的输出。当然,无论你使用什么接口都必须理解hstore和数组,否则你必须自己解压缩结果;如果是这种情况,迭代简单的select attr, val from t1查询并在JavaScript中构建数据结构可能会更简单。