在 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
范围?框架规范没有帮助,因为它都是基于行的。
我对使用子查询的替代解决方案不感兴趣,它必须基于窗口处理。
答案 0 :(得分: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标准就没有任何保证,并且它可能会在更复杂的查询中中断。
相关:
答案 1 :(得分:1)
我不认为有任何语法意味着&#34;当前行&#34;在表达中。 postgres的gram.y文件制作了一个过滤子句 只需要一个a_expr,这只是正常的表达式子句。那里 并不特定于表达式中的窗口函数或过滤子句。 据我所知,window子句中唯一的当前行概念是用于指定窗口框架边界。我不认为这会抓住你 你想要什么。
您可以从封闭的查询中获得一些吸引力:
http://www.postgresql.org/docs/current/static/sql-expressions.html
当子表达式中出现聚合表达式时(参见第4.2.11节) 和9.22节),通常在行上评估聚合 子查询。但是如果聚合的参数发生异常 (和filter_clause,如果有的话)只包含外层变量: 聚合然后属于最近的这样的外层,并且是 评估该查询的行。
但这对我来说并不明显。