我有一个名为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语句。
这些查询的语法是什么?
答案 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
此时,由于事物更加规范化,您可以根据需要使用常规查询进行混合和匹配。 (您可以先将上述查询的结果放在temp table
中。)