引用窗口函数的FILTER子句中的当前行

问题描述 投票:11回答:2

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

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

col1 | col2 |     dt
------------------------
  1  |  a   | 2015-07-01
  2  |  b   | 2015-07-03
  3  |  c   | 2015-07-10
  4  |  d   | 2015-07-11
  5  |  e   | 2015-07-11
  6  |  f   | 2015-07-13
...

在整个表格上对date进行处理的窗口定义非常简单:WINDOW win AS (ORDER BY dt)

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

col1 | col2 |     dt     | count
--------------------------------
  1  |  a   | 2015-07-01 |   1
  2  |  b   | 2015-07-03 |   2
  3  |  c   | 2015-07-10 |   1
  4  |  d   | 2015-07-11 |   3
  5  |  e   | 2015-07-11 |   3
  6  |  f   | 2015-07-13 |   4
...

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

count(*) FILTER (WHERE current_row.dt - dt <= 4) OVER win

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

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

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

sql postgresql window-functions postgresql-9.4
2个回答
5
投票

您实际上并没有聚合行,因此新的聚合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.

有关:


1
投票

我认为在表达式中没有任何语法意味着“当前行”。 postgres的gram.y文件使得一个过滤子句只带一个a_expr,它只是普通的表达式子句。表达式中没有特定于窗口函数或过滤器子句的内容。据我所知,window子句中唯一的当前行概念是用于指定窗口框架边界。我不认为这会让你得到你想要的东西。

您可以通过封闭查询获得一些牵引力:

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

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

但这对我来说并不明显。

© www.soinside.com 2019 - 2024. All rights reserved.