【问题标题】:Count rows in partition with Order By使用 Order By 计算分区中的行数
【发布时间】:2018-11-29 10:12:21
【问题描述】:

我试图通过编写一些示例查询来理解 postgres 中的 PARTITION BY。我有一个运行查询的测试表。

id integer | num integer
___________|_____________
1          | 4 
2          | 4
3          | 5
4          | 6

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

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

id         | count
___________|_____________
1          | 2 
2          | 2
3          | 1
4          | 1

但是,当我将 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

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

【问题讨论】:

  • 第二种情况,postgre统计id小于等于实际id的行数
  • @RadimBača 是 postgres 特有的东西还是它应该如何工作?我不明白查询是如何按照您描述的方式解释的。
  • 使用 COUNT(*) 代替 COUNT(id) 得到相同的结果。
  • the documentation关于窗口函数,特别是:By default, if ORDER BY is supplied then the frame consists of all rows from the start of the partition up through the current row, plus any following rows that are equal to the current row according to the ORDER BY clause. When ORDER BY is omitted the default frame consists of all rows in the partition.
  • 感谢您的信息。我现在明白发生了什么。我错过了文档中提供的信息。

标签: sql postgresql window-functions


【解决方案1】:

当您将order by 添加到用作窗口函数的聚合时,该聚合变成“运行计数”(或您使用的任何聚合)。

count(*) 将根据指定的顺序返回“当前行”之前的行数。

以下查询显示了与 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;

将导致:

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

Postgres manual中有更多例子

【讨论】:

  • 这很有帮助。我可能应该详细阅读手册;)
  • with test (id, num, x) as ( values (1, 4, 1), (2, 4, 1), (3, 5, 2), (4, 6, 2) ) SQL Server 中是否有类似的语法?
【解决方案2】:

你的两个表达是:

COUNT(id) OVER (PARTITION BY num)

COUNT(id) OVER (PARTITION BY num ORDER BY id)

您为什么希望它们返回相同的值?语法不同是有原因的。

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

第二个进行累积计数。它对id 的每一行执行COUNT(),对于直到ids 值的所有值。

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

COUNT(id) OVER (PARTITION BY num ORDER BY id RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

RANK() 略有不同。仅当 ORDER BY 键有关联时,差异才有意义。

【讨论】:

  • "你为什么希望这些返回相同的值?"因为排序通常对sql中的过滤没有影响。 WHERE 子句在排序之前应用。当语法表明它“在分区上”应用时,它对函数的影响远非显而易见。相反,一个关于如何在排序的情况下获得相同结果的示例会很好。
  • @dube 。 . .这不是结果集的排序子句。它是一个排序子句,是窗口函数的一部分。
  • 我知道并且我理解其中的区别。您的介绍声称显然存在差异,但我声称事实并非如此。如果不阅读文档中的详细信息,就无法预见。
【解决方案3】:

“为什么”已经被其他人解释过了。有时你有一个有序的窗口,尽管有一个ORDER BY,但你必须对整个分区进行计数。

为此,请使用unbounded rangeRANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

create table search_log
(
    id bigint not null primary key,
    query varchar(255) not null,
    stemmed_query varchar(255) not null,
    created timestamp not null,
);

SELECT query,
       created as seen_on,
       first_value(created) OVER query_window as last_seen,
       row_number() OVER query_window AS rn,
       count(*) OVER query_window AS occurence
FROM search_log l
     WINDOW query_window AS (PARTITION BY stemmed_query ORDER BY created DESC 
         RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    • 2016-04-24
    • 2015-01-08
    • 2016-12-09
    • 2020-01-14
    相关资源
    最近更新 更多