Postgresql

在 PostgreSQL 中為滾動總和設置非負下限

  • July 7, 2020

這是一個非常有趣的問題(詢問 SQL Server),我想試試看它是如何在 PostgreSQL 中完成的。讓我們看看是否有其他人可以做得更好。拿著這些數據,

CREATE TABLE foo
AS
 SELECT pkid::int, numvalue::int, groupid::int
 FROM ( VALUES
   ( 1,  -1   , 1 ),
   ( 2,  -2   , 1 ),
   ( 3,  5    , 1 ),
   ( 4,  -7   , 1 ),
   ( 5,  1    , 2 )
 ) AS t(pkid, numvalue, groupid);

我們正在嘗試生成這個:

PKID   RollingSum    GroupID
----------------------------- ## Explanation: 
1      0             1        ## 0 - 1 < 0  => 0
2      0             1        ## 0 - 2 < 0  => 0
3      5             1        ## 0 + 5 > 0  => 5
4      0             1        ## 5 - 7 < 0  => 0

問題描述為,

當添加負數將導致和為負時,將啟動限制以將結果設置為零。後續的加法應該基於這個調整後的值,而不是原來的滾動和。

使用加法應該達到預期的結果。如果第四個數字從 -7 變為 -3,則第四個結果應該是 2 而不是 0

如果可以提供一個總和而不是幾個滾動數字,那也是可以接受的。我可以使用儲存過程來實現非負加法,但這太低級了。

現實生活中的問題是我們將下訂單記錄為正數,將取消記錄為負數。由於連接問題,客戶可能會多次點擊該cancel按鈕,這將導致記錄多個負值。在計算我們的收入時,“零”需要作為銷售的邊界。

他們的解決方案都是使用遞歸。

這就是我使用嵌套 OLAP 函式在 Teradata 上解決類似問題的方法:

SELECT dt.*,
  -- find the lowest previous CumSum < 0       
  -- and adjust the current CumSum to zero
  Max(CASE WHEN CumSum < 0 THEN -CumSum ELSE 0 end)
      Over (PARTITION BY groupid
            ORDER BY pkid
            ROWS Unbounded Preceding)
  + CumSum AS AdjustedSum
FROM 
( 
  SELECT pkid, numvalue, groupid,
     -- calculate a standard cumulative sum
     Sum(numvalue)
     Over (PARTITION BY groupid
           ORDER BY pkid
           ROWS Unbounded Preceding) AS CumSum
  FROM foo
) AS dt

使用自定義聚合函式

我們CREATE FUNCTION用來創建一個int_add_pos_or_zero添加數字的函式,但如果它們小於 0,則返回 0。

CREATE FUNCTION int_add_pos_or_zero(int, int)
RETURNS int
AS $$
 BEGIN
   RETURN greatest($1 + $2, 0);
 END;
$$
LANGUAGE plpgsql
IMMUTABLE;

現在我們CREATE AGGREGATE就可以在視窗函式中執行它了。我們設置INITCOND=0.

CREATE AGGREGATE add_pos_or_zero(int) (
 SFUNC = int_add_pos_or_zero,
 STYPE = int,
 INITCOND = 0
);

現在我們像任何其他視窗函式一樣查詢它。

SELECT pkid,
 groupid,
 numvalue,
 add_pos_or_zero(numvalue) OVER (PARTITION BY groupid ORDER BY pkid)
FROM foo;
pkid | groupid | numvalue | add_pos_or_zero 
------+---------+----------+-----------------
   1 |       1 |       -1 |               0
   2 |       1 |       -2 |               0
   3 |       1 |        5 |               5
   4 |       1 |       -7 |               0
   5 |       2 |        1 |               1
(5 rows)

引用自:https://dba.stackexchange.com/questions/179367