Sha*_*vil 3 postgresql recursive
我有一张balances
表,current_balance
用于存储银行账户;以及一个transfers
表格,其中包含每次转账到账户和从账户转账的行(存款为正数,取款为负数)。
我需要创建一个帐户摘要,其中包含帐户的每次转账,以及该转账产生的余额。
例子:
+--------------------------+--------+---------+
| activity_date | amount | balance |
+--------------------------+--------+---------+
| 2015-12-24T20:27:00.670Z | 10 | 180 |
| 2015-12-19T12:13:50.085Z | -275 | 170 |
| 2015-12-18T23:56:22.513Z | 10 | 445 |
| 2015-12-18T23:54:46.880Z | 50 | 435 |
| 2015-12-17T03:32:10.707Z | -120 | 385 |
| 2015-12-12T03:56:50.775Z | 35 | 505 |
| 2015-12-11T23:09:40.211Z | -20 | 470 |
| 2015-12-03T01:17:59.460Z | -10 | 490 |
| 2015-11-23T15:39:35.003Z | 500 | 500 |
+--------------------------+--------+---------+
Run Code Online (Sandbox Code Playgroud)
由于我只有该帐户的当前余额,因此我需要从那里开始并返回到给定日期。在电子表格中,我会通过从以前的余额中减去转账金额来计算新余额,但是我无法将其转换为 SQL。
CREATE SCHEMA temp;
CREATE TABLE temp.balances (
account_id INT
, current_balance INT
);
CREATE TABLE temp.transfers (
account_id INT
, activity_date TIMESTAMP
, amount INT
);
INSERT INTO temp.balances (account_id, current_balance)
VALUES (1, 180);
INSERT INTO temp.transfers (account_id, activity_date, amount)
VALUES (1, '2015-12-24T20:27:00.670Z', 10)
, (1, '2015-12-19T12:13:50.085Z', -275)
, (1, '2015-12-18T23:56:22.513Z', 10)
, (1, '2015-12-18T23:54:46.880Z', 50)
, (1, '2015-12-17T03:32:10.707Z', -120)
, (1, '2015-12-12T03:56:50.775Z', 35)
, (1, '2015-12-11T23:09:40.211Z', -20)
, (1, '2015-12-03T01:17:59.460Z', -10)
, (1, '2015-11-23T15:39:35.003Z', 500);
Run Code Online (Sandbox Code Playgroud)
WITH transfers AS (
SELECT *
FROM temp.transfers
WHERE account_id = 1
AND activity_date BETWEEN '2015-10-01'::DATE AND CURRENT_TIMESTAMP
ORDER BY activity_date DESC
)
SELECT
t.activity_date
, t.amount
, (LAG(balance, 1, b.current_balance) OVER (ORDER BY t.activity_date DESC)::INT) - (LAG(t.amount, 1, 0) OVER (ORDER BY t.activity_date DESC)::INT) AS balance
FROM transfers t
JOIN temp.balances b ON b.account_id = t.account_id
Run Code Online (Sandbox Code Playgroud)
此查询失败,因为我试图访问由窗口函数生成的余额值。我研究了WITH RECURSIVE,这似乎是使用正确的技术,但无法让它发挥作用。我也不确定它是否可以与其他 WITH 子句结合使用,而我需要这样做。
所以我的问题是:在PostgreSQL 9.3 中,如何计算每次转账后的余额,从当前余额向后计算?
使用下面 Julien 答案的稍微修改版本,我尝试了这个:
WITH transfers AS (
SELECT *
FROM temp.transfers
WHERE account_id = 1
AND activity_date BETWEEN '2015-10-01'::DATE AND CURRENT_TIMESTAMP
)
SELECT
t.activity_date
, t.amount
, b.current_balance - SUM(t.amount) OVER(ORDER BY t.activity_date DESC) AS balance
FROM transfers t
JOIN temp.balances b ON b.account_id = t.account_id
Run Code Online (Sandbox Code Playgroud)
...这几乎是正确的,只是余额向上移动了一行。
你确实需要一个窗口函数。然而,滞后不是正确的。SUM(...) OVER(...)
是你想要的。请参阅SQL 小提琴。
SELECT account_id, activity_date, amount
, SUM(amount) OVER(PARTITION BY account_id ORDER BY activity_date) as balance
FROM transfers t
ORDER BY account_id, activity_date DESC;
Run Code Online (Sandbox Code Playgroud)
account_id | activity_date | amount | balance
1 | 2015-12-24 20:27:00.6700000 | 10 | 180
1 | 2015-12-19 12:13:50.0850000 | -275 | 170
1 | 2015-12-18 23:56:22.5130000 | 10 | 445
1 | 2015-12-18 23:54:46.8800000 | 50 | 435
1 | 2015-12-17 03:32:10.7070000 | -120 | 385
1 | 2015-12-12 03:56:50.7750000 | 35 | 505
1 | 2015-12-11 23:09:40.2110000 | -20 | 470
1 | 2015-12-03 01:17:59.4600000 | -10 | 490
1 | 2015-11-23 15:39:35.0030000 | 500 | 500
Run Code Online (Sandbox Code Playgroud)