【问题标题】:How to SUM() over column with reset condition?如何在具有重置条件的列上求和()?
【发布时间】:2016-04-14 14:48:42
【问题描述】:

我使用的是 Postgresql 9.2,我需要将数量从底部向上求和,初始值为 100,但是如果遇到名称为 X 的行,我需要从该行中 qty 的值重新开始求和。

例如:

itemorder   name    qty
  1          A       -20
  2          A2       350
  3          X        40
  4          A        50
  5          A        -10
  6          A2       10

应该生成:

itemorder   name    qty       modifyed_sum
  1          A       -20          20       / 40 + (-20)
  2          A2       350         40       / not A
  3          X        40           40       / encounter X, restart sum with X qty.
  4          A        50          140       / 90 + 50
  5          A        -10         90        / 100 +  (-10)
  6          A2       10          100       / not A

我用这个查询来求和:

SELECT 100 + Sum(CASE WHEN name = 'a' THEN qty ELSE 0 END)OVER(ORDER BY itemorder DESC) as modifyed_sum,
       qty,
       name,
       itemorder
FROM   Table_Name
ORDER  BY itemorder ASC

如何修改它以处理 X 案例? (可以有多个 X)

【问题讨论】:

  • 看不懂SUM()algorithm,能详细点吗?
  • 我已经在每一行附近解释了它是如何工作的。请注意,总和是 BUTTOM UP 而不是 TOP DOWN。这是我之前的问题:stackoverflow.com/questions/34487883/…当前问题扩展它。

标签: sql postgresql


【解决方案1】:

你需要一个RECURSIVE查询

SQL FIDDLE DEMO

WITH RECURSIVE t("itemorder", "name", "qty", "modifyed_sum", "level") AS (
    SELECT "itemorder", 
           "name", 
           "qty", 
           100 +  CASE 
                     WHEN "name" = 'A' THEN "qty"
                     ELSE 0
                  END as "modifyed_sum",
           "itemorder" as "level"
     FROM myTable
     WHERE "itemorder" = (SELECT max("itemorder") FROM myTable)
     UNION ALL
     SELECT myTable."itemorder", 
            myTable."name", 
            myTable."qty", 
            CASE 
                WHEN myTable."name" = 'A' THEN t."modifyed_sum" + myTable."qty"
                WHEN myTable."name" = 'X' THEN myTable."qty"
                ELSE t."modifyed_sum"          
            END as "modifyed_sum",
           myTable."itemorder" as "level"
     FROM myTable 
     JOIN t
       ON myTable."itemorder" + 1 = t."itemorder" 
      AND myTable."itemorder" = t."level" - 1
     WHERE  myTable."itemorder" > 0        
)
SELECT *
FROM t
ORDER BY "itemorder"

输出

| itemorder | name | qty | modifyed_sum | level |
|-----------|------|-----|--------------|-------|
|         1 |    A | -20 |           20 |     1 |
|         2 |   A2 | 350 |           40 |     2 |
|         3 |    X |  40 |           40 |     3 |
|         4 |    A |  50 |          140 |     4 |
|         5 |    A | -10 |           90 |     5 |
|         6 |   A2 |  10 |          100 |     6 |

【讨论】:

  • 窗口函数中没有RESET命令吗?它在stackoverflow.com/questions/13819710/…
  • RESET真的可行吗?
  • @MarlonAbeykoon:链接的问题是关于 Teradata,而不是 Postgres。 Postgres 没有用于窗口定义的RESET 选项
【解决方案2】:

要根据条件重置窗口聚合,您需要添加另一个级别来定义不同的行组:

with cte as
 (
   select itemorder, name, qty,
      case -- start qty for each group
         when itemorder = max(itemorder) over () then 100 -- newest row
         when name = 'X' then qty
         else 0
      end 
           -- only sum 'A' rows
      + case when name = 'A' then qty else 0 end as new_qty, 

           -- grp value increases only when name = 'X'
           -- this assigns the same value to each row in a group
           -- will be used in the next step to PARTITION BY
      sum(case when name = 'X' then 1 else 0 end) 
      over (order by itemorder desc
            rows unbounded preceding) as grp
   from myTable
 )

select itemorder, name, qty,
   sum(new_qty)
   over (partition by grp
         order by itemorder desc
         rows unbounded preceding ) as modified_sum
from cte
order by item order

fiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 2018-05-02
    • 2013-04-14
    • 2021-10-02
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    相关资源
    最近更新 更多