使用PostgreSQL数组列出理解

时间:2014-08-26 22:51:15

标签: sql postgresql compositetype

我有一个名为composite_author的PostgreSQL表,在posts字段中有一个用户类型的数组。

select * from composite_author

|id |name |posts                                        |
|---|-----|---------------------------------------------|
|1  |john |{"(2,1,\"new post\")","(1,1,\"first post\")"}|
|2  |edgar|{"(3,2,\"hello world\")"}|                   |

posts列中的用户类型具有列名id,author_id,post_text。

我想编写一个查询,生成一个具有id和name列的结果,以及一个包含表示每个帖子文本的字符串数组的列。理想的输出如下:

|id |name |posts                                        |
|---|-----|---------------------------------------------|
|1  |john |{"new post","first post"}                    |
|2  |edgar|{"hello world"}                              |

执行其他类型的操作也很不错,例如返回仅包含post id和post文本的元组数组,或者根据某些条件过滤数组元素。从本质上讲,我有点像我的选择,在python中表现得像列表理解,或者在C#中表现简单的linq语句。

这些查询的语法是什么?

2 个答案:

答案 0 :(得分:2)

将用户类型post设为

create type post as (
    id int,
    author_id int,
    post_text text
);

composite_author表格为

create table composite_author (
    id int,
    name text,
    posts post[]
);
insert into composite_author (id, name, posts) values
(1, 'john', '{"(2,1,\"new post\")","(1,1,\"first post\")"}'),
(2, 'edgar', '{"(3,2,\"hello world\")"}');

然后基本查询是

select id, name, (p).id as post_id, (p).author_id, (p).post_text
from (
    select id, name, unnest(posts) as p
    from composite_author
) s;
 id | name  | post_id | author_id |  post_text  
----+-------+---------+-----------+-------------
  1 | john  |       2 |         1 | new post
  1 | john  |       1 |         1 | first post
  2 | edgar |       3 |         2 | hello world

可以将其转换为视图

create view view_composite_author as
select id, name, (p).id as post_id, (p).author_id, (p).post_text
from (
    select id, name, unnest(posts) as p
    from composite_author
) s;

然后基本查询变得更简单

select *
from view_composite_author;

字符串数组:

select id, name, array_agg(post_text)
from view_composite_author
group by id, name;
 id | name  |         array_agg         
----+-------+---------------------------
  1 | john  | {"new post","first post"}
  2 | edgar | {"hello world"}

包含post_id和post_text

的元组数组
select array_agg((post_id, post_text))
from view_composite_author;
                            array_agg                            
-----------------------------------------------------------------
 {"(2,\"new post\")","(1,\"first post\")","(3,\"hello world\")"}

过滤

select array_agg((post_id, post_text))
from view_composite_author
where author_id = 1;
                 array_agg                 
-------------------------------------------
 {"(2,\"new post\")","(1,\"first post\")"}

答案 1 :(得分:1)

我强烈建议正常化这些数据,如果可能的话,因为所有东西都被捣碎在一起,这样可能会非常严格。

但是,您可以根据当前数据尝试以下内容:

create table foo
(
  id integer,
  name text,
  posts text[]
);

insert into foo (id, name, posts)
  values 
      (1, 'john',  '{{"(2,1,\"new post\")"}, {"(1,1,\"first post\")"}}'),
      (2, 'edgar', '{"(3,2,\"hello world\")"}');

with indiv_strs AS
(
select id, name, unnest(posts) as post
from foo
)
select id, name, unnest(regexp_matches(post, E'\"(.+)\"')) as filtered_post
from indiv_strs;

这导致输出如下:

1   john    new post
1   john    first post
2   edgar   hello world

sqlfiddle

此时,由于事物更加规范化,您可以根据需要使用常规查询进行混合和匹配。 (您可以先将上述查询的结果放在temp table中。)