【问题标题】:PostgreSQL, two windowing functions at oncePostgreSQL,一次有两个窗口函数
【发布时间】:2016-08-10 06:45:22
【问题描述】:

我有典型的数据表,比如mytemptable

DROP TABLE IF EXISTS mytemptable; 
CREATE TEMP TABLE mytemptable 
       (mydate date, somedoc text, inqty int, outqty int); 
INSERT INTO mytemptable (mydate, somedoc, inqty, outqty) 
VALUES ('01.01.2016.', '123-13-24', 3, 0), 
       ('04.01.2016.', '15-19-44',  2, 0), 
       ('06.02.2016.', '15-25-21',  0, 1), 
       ('04.01.2016.', '21-133-12', 0, 1), 
       ('04.01.2016.', '215-11-51', 0, 2), 
       ('05.01.2016.', '11-181-01', 0, 1), 
       ('05.02.2016.', '151-80-8',  4, 0), 
       ('04.01.2016.', '215-11-51', 0, 2), 
       ('07.02.2016.', '34-02-02',  0, 2); 

SELECT row_number() OVER(ORDER BY mydate) AS rn, 
       mydate, somedoc, inqty, outqty, 
       SUM(inqty-outqty) OVER(ORDER BY mydate) AS csum 
  FROM mytemptable 
 ORDER BY mydate; 

在我的 SELECT 查询中,我尝试按日期排序结果并添加行号“rn”和累积(通过)总和“csum”。当然不成功。
我相信这是因为我在查询中使用了两个以某种方式发生冲突的窗口函数。

如何正确地使此查询快速、有序并在“csum”列(3、5、4、2、0、-1、3、2、0)中获得正确的结果

【问题讨论】:

    标签: postgresql window-functions


    【解决方案1】:

    由于2016-04-01 存在排序关系,因此这些行的结果将是总和。如果您希望它与众不同,请使用 order by 中的解开列。

    From the manual:

    还有一个与窗口函数相关的重要概念:对于每一行,在其分区内都有一组行,称为窗口框架。许多(但不是全部)窗口函数只作用于窗框的行,而不作用于整个分区。默认情况下,如果提供了 ORDER BY,则该框架由从分区开始到当前行的所有行以及根据 ORDER BY 子句等于当前行的任何后续行组成。省略 ORDER BY 时,默认框架由分区中的所有行组成

    如果没有解绑列,您可以在外部查询中使用生成的行号:

    set datestyle = 'dmy';
    with mytemptable (mydate, somedoc, inqty, outqty) as (
        values
        ('01-01-2016'::date, '123-13-24', 3, 0), 
        ('04-01-2016', '15-19-44',  2, 0), 
        ('06-02-2016', '15-25-21',  0, 1), 
        ('04-01-2016', '21-133-12', 0, 1), 
        ('04-01-2016', '215-11-51', 0, 2), 
        ('05-01-2016', '11-181-01', 0, 1), 
        ('05-02-2016', '151-80-8',  4, 0), 
        ('04-01-2016', '215-11-51', 0, 2), 
        ('07-02-2016', '34-02-02',  0, 2)
    )
    select *, sum(inqty-outqty) over(order by mydate, rn) as csum
    from (
        select
            row_number() over(order by mydate) as rn, 
            mydate, somedoc, inqty, outqty
        from mytemptable
    ) s
    order by mydate;
     rn |   mydate   |  somedoc  | inqty | outqty | csum 
    ----+------------+-----------+-------+--------+------
      1 | 2016-01-01 | 123-13-24 |     3 |      0 |    3
      2 | 2016-04-01 | 15-19-44  |     2 |      0 |    5
      3 | 2016-04-01 | 21-133-12 |     0 |      1 |    4
      4 | 2016-04-01 | 215-11-51 |     0 |      2 |    2
      5 | 2016-04-01 | 215-11-51 |     0 |      2 |    0
      6 | 2016-05-01 | 11-181-01 |     0 |      1 |   -1
      7 | 2016-05-02 | 151-80-8  |     4 |      0 |    3
      8 | 2016-06-02 | 15-25-21  |     0 |      1 |    2
      9 | 2016-07-02 | 34-02-02  |     0 |      2 |    0
    

    【讨论】:

    • 这听起来很科学。但是你得到的结果和我的一样,说不正确或不需要。我可以通过两个查询获得想要的结果,其中首先添加行号,然后在第二个中我 ORDER BY rn,mydate。但我虽然也许有些人可能会用一个查询来做到这一点。真实数据量大,性能很重要。
    • @user1697111 已更新
    • 感谢科罗拉多。这似乎是解决方案。现在我必须研究它。但结果如预期。我必须注意,在我的系统和 pgAdmin III 行“set date style = 'dmy';”导致语法错误。我也可以用欧洲风格写日期,而无需投射“::date”。这个查询是比两个单独的查询快还是需要同样的时间?
    • @user1697111 它比两个单独的查询要快。它是datestyle,没有空格。现在修好了。对于使用ISO 样式的人来说,该日期样式设置是必需的。
    猜你喜欢
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    相关资源
    最近更新 更多