Jar*_*bzo 9 postgresql aggregate order-by subquery
我的问题的小提琴可以在https://dbfiddle.uk/?rdbms=postgres_10&fiddle=3cd9335fa07565960c1837aa65143685上找到。
我有一个简单的表格布局:
class
person: belongs to a class
Run Code Online (Sandbox Code Playgroud)
我想选择所有班级,对于每个班级,我想要按降序排列的所属人员的前两个人员标识符。
我通过以下查询解决了这个问题:
select c.identifier, array_agg(p.identifier order by p.name desc) as persons
from class as c
left join lateral (
select p.identifier, p.name
from person as p
where p.class_identifier = c.identifier
order by p.name desc
limit 2
) as p
on true
group by c.identifier
order by c.identifier
Run Code Online (Sandbox Code Playgroud)
注意:我可以在SELECT
子句中使用相关子查询,但作为学习过程的一部分,我试图避免这种情况。
如您所见,我order by p.name desc
在两个地方申请:
有没有办法避免这种情况?我的坚持:
首先,显然我不能删除order by
子查询中的 ,因为这会给出一个不符合我上述要求的查询。
其次,我认为order by
聚合函数中的 不能被遗漏,因为子查询的行顺序不一定保留在聚合函数中?
我应该重写查询吗?
我
order by p.name desc
在两个地方申请......有没有办法避免这种情况?
是的。直接在横向子查询中使用ARRAY 构造函数聚合:
SELECT c.identifier, p.persons
FROM class c
CROSS JOIN LATERAL (
SELECT ARRAY (
SELECT identifier
FROM person
WHERE class_identifier = c.identifier
ORDER BY name DESC
LIMIT 2
) AS persons
) p
ORDER BY c.identifier;
Run Code Online (Sandbox Code Playgroud)
你也不需要GROUP BY
在外面SELECT
这样。更短、更干净、更快。
因为 ARRAY 构造函数总是准确返回 1 行,所以我LEFT JOIN
用一个普通的替换了CROSS JOIN
。(就像你在评论中指出的那样。)
有关的:
要解决您的评论:
我了解到子查询中的行顺序永远不能保证在外部查询中保留。
嗯,不。虽然 SQL 标准不提供任何保证,但Postgres 中的保证有限。手册:
默认情况下,此顺序未指定,但可以通过
ORDER BY
在聚合调用中编写子句来控制,如第 4.2.7 节所示 。或者,从排序的子查询提供输入值通常会起作用。例如:Run Code Online (Sandbox Code Playgroud)SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
请注意,如果外部查询级别包含附加处理(例如连接),则此方法可能会失败,因为这可能会导致在计算聚合之前对子查询的输出进行重新排序。
如果您在下一级别中所做的只是聚合行,则肯定会保证顺序。是的,我们提供给 ARRAY 构造函数的也是一个子查询。这不是重点。它也适用于array_agg()
:
SELECT c.identifier, p.persons
FROM class c
CROSS JOIN LATERAL (
SELECT array_agg(identifier) AS persons
FROM (
SELECT identifier
FROM person
WHERE class_identifier = c.identifier
ORDER BY name DESC
LIMIT 2
) sub
) p
ORDER BY c.identifier;
Run Code Online (Sandbox Code Playgroud)
但我希望 ARRAY 构造函数在这种情况下更快。看:
归档时间: |
|
查看次数: |
5936 次 |
最近记录: |