在嵌套的array_agg查询中进行排序

时间:2017-10-17 18:09:37

标签: postgresql

我对此查询的目标是从communities表中提取所有内容,以及从array_agg jsonbselect communities.*, ( select array_agg(jsonb_build_object('id', community_permissions.document_id)) from documents as conversations join community_permissions on community_permissions.document_id = conversations.id where conversations.published = true and community_permissions.community_id = communities.id ) as conversations from communities where communities.id = 110; 个对象中提取所有内容。这样就可以在未分类的情况下正常工作:

communities

这将为[{ id: 1 }, { id: 2 } ...]中的列返回一个包含普通列的行,并在conversations列中返回一个类似select communities.*, ( select array_agg(jsonb_build_object('id', community_permissions.document_id)) from documents as conversations join community_permissions on community_permissions.document_id = conversations.id where conversations.published = true and community_permissions.community_id = communities.id order by conversations.updated_at desc ) as conversations from communities where communities.id = 110; 的json数组。一切都很好,查询工作得很好,我可以在SQL中声明性地获取一行及其重要的关系。我甚至可以从另一个表中过滤连接的返回值(在此列表中只返回已发布的对话)。

我现在要做的是根据文档表中的属性对对话进行排序(别名为上面的对话)。天真的方法:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id))
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
        where conversations.published = true
        and community_permissions.community_id = communities.id
        group by conversations.updated_at
        order by conversations.updated_at desc
  ) as conversations
  from communities where communities.id = 110;

不起作用 - 列walker希望conversations.updated_at值在group_by子句中。如果我像这样添加group by子句:

limit 1

看起来array_agg实际上不再聚合响应 - 我得到一个错误“由用作表达式的子查询返回的多行”。我可以在order by之后放置一个with q1 as ( select conversations.id as id, community_permissions.community_id as community_id from documents as conversations join community_permissions on community_permissions.document_id = conversations.id where conversations.published = true order by conversations.updated_at desc ) select communities.id, ( select array_agg(jsonb_build_object('id', q1.id))) as conversations from communities join q1 on q1.community_id = communities.id where communities.id = 110 group by communities.id; ,然后执行查询,但之后我只在array_agg列中进行一次会话 - 至少是最近一次。所以看起来array_agg实际上并没有进入数组,可以这么说。

我可以通过将整个事物分开并使用CTE来执行此查询:

rowSums

但这非常低效,解释器表明它在每次查询运行时对整个会话表进行排序,并且任何给定的社区只有一小部分会话表通过community_permissions与之共享。

这也令人不满意,因为我正在尝试模块化我的查询,以便后端可以决定,“嘿,你将需要这些值”并将它们推送到SQL查询中并在一个查询中一次完成所有操作而不是拉动社区,然后手动查询每个关系(通常不止一个 - 社区有成员,对话,粉丝等)。最糟糕的情况是,我可以这样做 - 只需处理后端节点层中的额外提取并在那里进行组装,但将其全部放在子查询中似乎更优雅(直到我需要这种排序功能)。

2 个答案:

答案 0 :(得分:2)

其中一个“在stackoverflow上写了一篇很长的帖子并在十分钟后找到答案”的情况。

为了将来参考,诀窍是我把订单放在了错误的地方。这有效:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id) order by conversations.updated_at desc)
    from documents as conversations
      join community_permissions on community_permissions.document_id = conversations.id
      where conversations.published = true
      and community_permissions.community_id = communities.id
  ) as conversations
  from communities where communities.id = 110;

请注意,order by现在位于array_agg调用中,而不是在子查询内。

答案 1 :(得分:2)

您可以在聚合函数中指定顺序。

尝试:

select communities.*,
  (
    select array_agg(jsonb_build_object('id', community_permissions.document_id) order by conversations.updated_at desc)
    from documents as conversations
    join community_permissions on community_permissions.document_id = conversations.id
    where conversations.published = true
      and community_permissions.community_id = communities.id
  ) as conversations
from communities where communities.id = 110;