SQL累计计算每一行的差异

问题描述 投票:0回答:1

我有下表USERIDEOMONTHPendingcleared是实际的列。 Overdue_BalanceOverdue_since_date 是我需要导出的列。

我需要累计计算每个 EOMONTH 的 overdue_balance= sum(pending) - sum(Cleared) 以获得每个 EOMONTH 的 Overdue_Balance。如果存在任何 Overdue_balance,那么当存在 Overdue_balance 时,我需要将 Overdue_since_date 导出为 EOMONTH,并继续相同的 OVerdue_since_date 直到余额变为零。

enter image description here

下面是我尝试过的 SQL 查询 Overdue_Balance 正常出现,但 Overdue_since_date 没有按照我的要求出现,需要使用 SQL 帮助解决它

-- Create a table to store the sample data
CREATE TABLE sample_data (
    UserID integer,
    EOMONTH date,
    Pending integer,
    Cleared integer
);

-- Insert sample data into the table
INSERT INTO sample_data (UserID, EOMONTH, Pending, Cleared)
VALUES
    (1, '2024-05-31', 50, 110),
    (1, '2024-04-30', 100, 100),
    (1, '2024-03-31', 50, 0),
    (1, '2024-02-29', 50, 40),
    (1, '2024-01-31', 100, 100),
    (1, '2023-12-31', 50, 70),
    (1, '2023-11-30', 90, 80),
    (1, '2023-10-31', 100, 90);

-- Display the inserted data
WITH CumulativeSums AS (
    SELECT 
        UserID,
        EOMONTH,
        Pending,
        Cleared,
        SUM(Pending - Cleared) OVER (PARTITION BY UserID ORDER BY EOMONTH) AS Overdue_balance,
        CASE 
            WHEN Pending - Cleared < 0 THEN EOMONTH
            ELSE NULL
        END AS Overdue_since_date_flag
    FROM 
        sample_data
),

ResetPoints AS (
    SELECT 
        UserID,
        EOMONTH,
        Overdue_since_date_flag,
        LAG(Overdue_since_date_flag) OVER (PARTITION BY UserID ORDER BY EOMONTH) AS prev_flag
    FROM 
        CumulativeSums
)

SELECT 
    UserID,
    EOMONTH,
    Pending,
    Cleared,
    CASE 
        WHEN Overdue_balance < 0 THEN COALESCE(MAX(Overdue_since_date_flag) OVER (PARTITION BY UserID ORDER BY EOMONTH ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), EOMONTH)
        WHEN Overdue_balance >= 0 AND LAG(Overdue_balance) OVER (PARTITION BY UserID ORDER BY EOMONTH) < 0 THEN NULL
        ELSE COALESCE(MAX(Overdue_since_date_flag) OVER (PARTITION BY UserID ORDER BY EOMONTH ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), EOMONTH)
    END AS Overdue_since_date,
    Overdue_balance
FROM 
    CumulativeSums
ORDER BY 
    UserID, EOMONTH;
postgresql
1个回答
0
投票

您必须检测平衡 > 0 和不平衡 > 0 的行之间的破裂,以便能够通过间隙和岛屿分配组号,然后使用 first_value() 分析您将获得正确的日期:

SELECT d.userid, eomonth, pending, cleared, balance, CASE WHEN balance > 0 THEN
    FIRST_VALUE(eomonth) OVER(PARTITION BY UserID, grp ORDER BY eomonth) END AS since
FROM (
    SELECT d.*, SUM(rupt) OVER(PARTITION BY UserID ORDER BY eomonth) AS grp
    FROM (
        SELECT d.*, 
            CASE WHEN GREATEST(0,sign(LAG(balance,1,0) OVER(PARTITION BY UserID ORDER BY EOMONTH))) 
                = GREATEST(0,sign(balance)) THEN 0 ELSE 1 END AS rupt
        FROM (
            SELECT d.*, SUM(Pending - cleared) OVER(PARTITION BY UserID ORDER BY eomonth) AS balance
            FROM sample_data d
        ) d
    ) d
)
d
ORDER BY eomonth desc
;
© www.soinside.com 2019 - 2024. All rights reserved.