在postgres上创建深度嵌套的JSON结构而不必编写非常复杂的缩进查询的简单方法是什么?
我将几个表连接到一个postgres数据库中,并将右连接表中的值作为聚合JSON结构返回到左连接表中。然而,我发现,连接的表越多,查询就越复杂。例如:在postgres上创建深度嵌套的JSON结构而不必编写非常复杂的缩进查询的简单方法是什么?,json,postgresql,Json,Postgresql,我将几个表连接到一个postgres数据库中,并将右连接表中的值作为聚合JSON结构返回到左连接表中。然而,我发现,连接的表越多,查询就越复杂。例如: select row_to_json(output) from ( select image_type.name, ( select json_agg(instances) from ( select image_instance.name, (
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;
我在这里加入了三个表,但是我想再添加几个表,但是代码很快就会变得很难维护。有没有一种简单的方法来生成这种聚合联接?首先,当组合来自多个表的数据时,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;
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);
3。模块化
就在那里(强烈推荐阅读,无论你认为自己多么熟练):
充分利用视图是良好SQL数据库的一个关键方面
设计
您的主要查询现在变成:
select row_to_json(row(it.name, ii.name))
from image_type it
join ii_json ii using (image_type_id);
等等
这显然是迄今为止最容易编码、测试和维护的。性能在这里不是问题:查询优化器将把所有链接视图展平到单个执行计划中
最后一点提示:如果您使用的是PG9.4+,您可以使用
json\u build\u object()
而不是行到行的json()
,以获得更清晰的输出。@a\u horse\u没有名字的马\u您能在此基础上进行扩展吗?我阅读了您引用的文章,但是我的数据存储在标准化的表中,而不是JSON blob中。我只希望从这些表生成一个JSON主体。也许如果你能扩展一点,它会帮助我理解。谢谢你的回答@Patrick,这是非常全面的,并教会了我如何使用JSON视图。我试着按照您概述的方式来做,但是它们似乎不是嵌套的,而是分组在每列中。您能说明一种将每个连接嵌套为包含聚合的字段的方法吗?如果看不到表结构和所需的输出格式,很难说问题出在哪里,但您可能希望更改ii_json
视图并放置json_agg(json_build_object('instance',name',versions',iv_name))
而不是普通的json\u agg(name,iv\u name)
。与此类似,每一行将有一个JSON对象,该对象具有一个图像类型和一个实例数组,每个实例由一个名称和一个版本数组组成。这就是你想要的吗?
select row_to_json(row(it.name, ii.name))
from image_type it
join ii_json ii using (image_type_id);