我将 postgres 数据库中的几个表连接在一起,并将右连接表中的值作为左连接表中的聚合 JSON 结构返回。但是我发现连接的表越多,该查询就会变得越复杂。例如:
select row_to_json(output)
from (
select image_type.name,
(
select json_agg(instances)
from (
select image_instance.name, (
select json_agg(versions)
from (
select image_version.name
from image_version
where image_version.image_instance_id = image_version.image_instance_id
) versions
) AS versions
from image_instance
where image_instance.image_type_id = image_type.image_type_id
) instances
) AS images
from image_type
) output;
Run Code Online (Sandbox Code Playgroud)
我在这里加入了三个表,但是我想再添加几个表,但是代码很快就会变得笨拙且难以维护。有没有一种简单的方法来生成这些类型的聚合连接?
首先,在组合来自多个表的数据时,JSON 与常规字段没有什么不同:事情很快就会变得复杂。然而,有一些技巧可以让事情变得易于管理:
1. 菊花链功能
无需独立处理每个函数的输出,您可以在单个语句中将一个函数的输出作为下一个函数的输入。在您的示例中,这意味着您会丢失每个聚合级别的子选择级别,并且您可以忘记别名。你的例子变成:
select row_to_json(row(image_type.name, (
select json_agg(image_instance.name, (
select json_agg(image_version.name)
from image_version
where image_version.image_instance_id = image_instance.id) -- join edited
from image_instance
where image_instance.image_type_id = image_type.image_type_id))))
from image_type;
Run Code Online (Sandbox Code Playgroud)
2. 不要使用标量子查询
这可能是个人品味的问题,但标量子查询往往难以阅读(和编写:您在最里面的标量子查询的连接条件中有一个明显的错误,只是为了说明我的观点)。请改用具有显式连接和聚合的常规子查询:
select row_to_json(row(it.name, iiv.name))
from image_type it
join (select image_type_id, json_agg(name, iv_name) as name
from image_instance ii
join (select image_instance_id, json_agg(name) as iv_name
from image_version group by 1) iv on iv.image_instance_id = ii.id
group by 1) iiv using (image_type_id);
Run Code Online (Sandbox Code Playgroud)
3.模块化
就在文档开头的教程部分(强烈推荐阅读,无论您认为自己有多熟练):
充分使用视图是良好 SQL 数据库设计的一个关键方面。
create view iv_json as
select image_instance_id, json_agg(name) as iv_name
from image_version
group by 1;
create view ii_json as
select image_type_id, json_agg(name, iv_name) as name
from image_instance
join iv_json on image_instance_id = image_instance.id
group by 1;
Run Code Online (Sandbox Code Playgroud)
您的主要查询现在变为:
select row_to_json(row(it.name, ii.name))
from image_type it
join ii_json ii using (image_type_id);
Run Code Online (Sandbox Code Playgroud)
等等...
这显然是迄今为止最容易编码、测试和维护的。性能在这里不是问题:查询优化器会将所有链接的视图扁平化为单个执行计划。
最后注意:如果您使用的是 PG9.4+,您可以使用json_build_object()代替row_to_json()以获得更清晰的输出。
| 归档时间: |
|
| 查看次数: |
1950 次 |
| 最近记录: |