【问题标题】:Referencing current row in FILTER clause of window function在窗口函数的 FILTER 子句中引用当前行
【发布时间】:2015-10-02 11:43:41
【问题描述】:

PostgreSQL 9.4 中,窗口函数具有 FILTER 的新选项,用于选择窗口框架的子集进行处理。文档中提到了它,但没有提供示例。在线搜索会产生一些示例,包括来自 2ndQuadrant 的示例,但我发现的所有示例都是带有常量表达式的相当琐碎的示例。我正在寻找的是一个包含当前行值的过滤器表达式。

假设我有一个包含一堆列的表,其中一个是date 类型:

col1 | col2 | dt
----------------------
  1 |一个 | 2015-07-01
  2 |乙 | 2015-07-03
  3 | c | 2015-07-10
  4 | d | 2015-07-11
  5 |电子| 2015-07-11
  6 | f | 2015-07-13
...

在整个表上处理date 的窗口定义很简单:WINDOW win AS (ORDER BY dt)

我有兴趣知道当前行之前的 4 天(含)有多少行。所以我想生成这个输出:

col1 | col2 | dt |数数
--------------------------------
  1 |一个 | 2015-07-01 | 1
  2 |乙 | 2015-07-03 | 2
  3 | c | 2015-07-10 | 1
  4 | d | 2015-07-11 | 3
  5 |电子| 2015-07-11 | 3
  6 | f | 2015-07-13 | 4
...

窗口函数的FILTER 子句似乎是显而易见的选择:

count(*) FILTER (WHERE <b>current_row.dt</b> - dt &lt;= 4) OVER win

但是我如何指定current_row.dt(因为缺少更好的语法)?这甚至可能吗?

如果这是不可能的,还有其他方法可以在窗口框架中选择date 范围吗?框架规范无济于事,因为它都是基于行的。

我对使用子查询的替代解决方案不感兴趣,它必须基于窗口处理。

【问题讨论】:

  • 有趣的问题。作为 Postgres 常客,您应该知道提供表定义(或者更好的是,提供完整的 CREATE TABLE 脚本)
  • @ErwinBrandstetter 这是否值得标记为“功能请求”?对我来说,能够根据当前行中存在的某些条件过滤窗口框架似乎很有价值。
  • 是的,它对各种问题都有用,我在这里看到了几个相关的问题。由于实施中的主要变化,我担心该功能需要大量工作,但记录公众对该功能的兴趣并没有什么坏处。似乎与缺少的 RANGE BETWEEN ... PRECEDING/FOLLOWING 功能有关,该功能已经是 documented in the ToDo Wiki

标签: sql postgresql window-functions postgresql-9.4


【解决方案1】:

您实际上并没有聚合行,因此新的聚合FILTER 子句不是正确的工具。窗口函数更像它,但是问题仍然存在:窗口的frame definition 不能依赖于当前行的。它只能计算ROWS 子句前后的给定行数。

要实现这一点,请将每天的计数和 LEFT JOIN 汇总到范围内的完整天数。然后你可以应用一个窗口函数:

SELECT t.*, ct.ct_last4days
FROM  (
   SELECT *, sum(ct) OVER (ORDER BY dt ROWS 3 PRECEDING) AS ct_last4days
   FROM  (
      SELECT generate_series(min(dt), max(dt), interval '1 day')::date AS dt
      FROM   tbl t1
      ) d
   LEFT   JOIN (SELECT dt, count(*) AS ct FROM tbl GROUP BY 1) t USING (dt)
   ) ct
JOIN  tbl t USING (dt);

在寡妇框架定义中省略ORDER BY dt通常有效,因为订单是从子查询中的generate_series() 结转的。但是如果没有明确的ORDER BY,SQL 标准就无法保证,并且它可能会中断更复杂的查询。

SQL Fiddle.

相关:

【讨论】:

  • FILTER 子句适用于存在OVER 子句的聚合函数时,它们act as window functions (...) otherwise they act as regular aggregates 这样会使你的开场白无效,如果我正确理解文档和你的话。被接受为一个可行的解决方案和对细节的一丝不苟的关注,但只是不情愿地依赖于子查询,这显然不是你的错。
  • @Patrick:聚合函数(可以)折叠行,而窗口函数不能。您显然不想折叠行,因此您处于窗口函数的领域。 FILTER 子句为聚合函数实现了窗口函数的一些特性,但无论如何你都需要一个窗口函数。
【解决方案2】:

我认为表达式中没有任何表示“当前行”的语法。 postgres 的 gram.y 文件创建了一个过滤子句 只取一个 a_expr,这只是普通的表达式子句。那里 不是特定于表达式中的窗口函数或过滤子句的。 据我所知,window 子句中唯一的当前行概念是用于指定窗口框架边界。我不认为这让你 你想要什么。

您可能会从封闭查询中获得一些吸引力:

http://www.postgresql.org/docs/current/static/sql-expressions.html

当聚合表达式出现在子查询中时(参见第 4.2.11 节 和第 9.22 节),聚合通常在行上进行评估 的子查询。但是如果聚合的参数会发生异常 (和 filter_clause 如果有的话)只包含外层变量: 聚合则属于最近的这样的外部级别,并且是 对该查询的行进行评估。

但对我来说并不明显。

【讨论】:

    猜你喜欢
    • 2017-08-14
    • 2018-06-09
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多