使用Order By计算分区中的行数

kis*_*ore 2 sql postgresql window-functions

我试图通过编写一些示例查询来了解postgres中的PARTITION BY.我有一个测试表,我在其上运行查询.

id integer | num integer
___________|_____________
1          | 4 
2          | 4
3          | 5
4          | 6
Run Code Online (Sandbox Code Playgroud)

当我运行以下查询时,我得到了我预期的输出.

SELECT id, COUNT(id) OVER(PARTITION BY num) from test;

id         | count
___________|_____________
1          | 2 
2          | 2
3          | 1
4          | 1
Run Code Online (Sandbox Code Playgroud)

但是,当我将ORDER BY添加到分区时,

SELECT id, COUNT(id) OVER(PARTITION BY num ORDER BY id) from test;

id         | count
___________|_____________
1          | 1 
2          | 2
3          | 1
4          | 1
Run Code Online (Sandbox Code Playgroud)

我的理解是COUNT是在属于分区的所有行中计算的.在这里,我用num分区行.分区中的行数是相同的,有或没有ORDER BY子句.为什么输出会有差异?

a_h*_*ame 6

当您将一个order by聚合添加到用作窗口函数的聚合时,聚合将变为"运行计数"(或您使用的任何聚合).

count(*)将返回的行数,直到基于指定的顺序对"当前".

以下查询显示与a一起使用的聚合的不同结果order by.随着sum()代替count()它有点更容易看到(在我看来).

with test (id, num, x) as (
  values 
    (1, 4, 1),
    (2, 4, 1),
    (3, 5, 2),
    (4, 6, 2)
)
select id, 
       num,
       x,
       count(*) over () as total_rows, 
       count(*) over (order by id) as rows_upto,
       count(*) over (partition by x order by id) as rows_per_x,
       sum(num) over (partition by x) as total_for_x,
       sum(num) over (order by id) as sum_upto,
       sum(num) over (partition by x order by id) as sum_for_x_upto
from test;
Run Code Online (Sandbox Code Playgroud)

将导致:

id | num | x | total_rows | rows_upto | rows_per_x | total_for_x | sum_upto | sum_for_x_upto
---+-----+---+------------+-----------+------------+-------------+----------+---------------
 1 |   4 | 1 |          4 |         1 |          1 |           8 |        4 |              4
 2 |   4 | 1 |          4 |         2 |          2 |           8 |        8 |              8
 3 |   5 | 2 |          4 |         3 |          1 |          11 |       13 |              5
 4 |   6 | 2 |          4 |         4 |          2 |          11 |       19 |             11
Run Code Online (Sandbox Code Playgroud)

Postgres手册中有更多示例

  • 那非常有帮助。我可能应该详细阅读手册;) (2认同)

Gor*_*off 5

你的两个表达式是:

COUNT(id) OVER (PARTITION BY num)

COUNT(id) OVER (PARTITION BY num ORDER BY id)
Run Code Online (Sandbox Code Playgroud)

为什么您希望这些返回相同的值?出于某种原因,语法不同。

第一个返回每个num的总计数——本质上是连接聚合值。

第二个进行累积计数。它COUNT()为 的每一行id, 直到该ids 值的所有值都执行此操作。

请注意,此类累积计数通常会使用RANK()(或相关函数)实现。累积计数与 略有不同RANK()。累计计数实现:

COUNT(id) OVER (PARTITION BY num ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
Run Code Online (Sandbox Code Playgroud)

RANK()略有不同。只有当ORDER BY键有联系时,差异才重要。

  • “你为什么期望它们返回相同的值?” 因为排序通常对sql中的过滤没有影响。WHERE 子句在排序之前应用。当语法表明它“在分区上”应用时,它对函数的影响并不明显。相反,如果有一个关于如何在排序的情况下实现相同结果的示例就更好了。 (4认同)