我试图根据给定的表格数据计算调整后的成本基数,但无法弄清楚如何使用当前行中的先前计算值。
<script>
使用数据:
CREATE TABLE transactions (
datetime timestamp NOT NULL,
type varchar(25) NOT NULL,
amount INT NOT NULL,
shares INT NOT NULL,
symbol VARCHAR(20) NOT NULL
);
据我所知:
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (100, 'Buy', 10, now() - INTERVAL '14 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (330, 'Buy', 30, now() - INTERVAL '11 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (222, 'Buy', 22, now() - INTERVAL '10 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (245, 'Buy', 24, now() - INTERVAL '8 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (150, 'Sell', 15, now() - INTERVAL '7 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (210, 'Buy', 20, now() - INTERVAL '6 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (235, 'Buy', 22, now() - INTERVAL '5 days', 'XYZ');
INSERT INTO transactions(amount, type, shares, datetime, symbol) VALUES (110, 'Sell', 10, now() - INTERVAL '4 days', 'XYZ');
预期结果(total_acb是我尝试计算的值):
WITH cte AS (
WITH shares AS (
SELECT transactions.*,
sum(CASE WHEN transactions.type = 'Sell'
THEN transactions.shares * -1 --reduction of shares
ELSE transactions.shares END)
OVER (
PARTITION BY transactions.symbol
ORDER BY transactions.symbol, transactions.datetime ROWS UNBOUNDED PRECEDING ) AS total_shares
FROM transactions)
SELECT shares.*, coalesce(lag(shares.total_shares) OVER(ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) as previous_shares FROM shares)
SELECT cte.*,
CASE WHEN cte.type = 'Buy' THEN
-- [Previous total_acb] + cte.amount
ELSE
-- [Previous total_acb] x ((cte.previous_shares – shares) / cte.previous_shares)
END
AS total_acb
FROM cte
答案 0 :(得分:0)
进行这种递归计算的最简单方法是使用plpgsql函数。
create or replace function calculate_totals()
returns table (
datetime timestamp,
type text,
amount dec,
shares dec,
symbol text,
total_shares dec,
total_acb dec)
language plpgsql as $$
declare
rec record;
curr_symbol text = '';
begin
for rec in
select *
from transactions
order by symbol, datetime
loop
if rec.symbol <> curr_symbol then
curr_symbol = rec.symbol;
total_acb = 0;
total_shares = 0;
end if;
if rec.type = 'Buy' then
total_acb = round(total_acb + rec.amount, 2);
total_shares = total_shares + rec.shares;
else
total_acb = round(total_acb * (total_shares - rec.shares) / total_shares, 2);
total_shares = total_shares - rec.shares;
end if;
select rec.datetime, rec.type, rec.amount, rec.shares, rec.symbol
into datetime, type, amount, shares, symbol;
return next;
end loop;
end $$;
结果与问题中给出的结果略有不同(由于作者的错误):
select *
from calculate_totals();
datetime | type | amount | shares | symbol | total_shares | total_acb
---------------------------+------+--------+--------+--------+--------------+-----------
2018-01-10 23:28:56.66738 | Buy | 100 | 10 | XYZ | 10 | 100.00
2018-01-13 23:28:56.66738 | Buy | 330 | 30 | XYZ | 40 | 430.00
2018-01-14 23:28:56.66738 | Buy | 222 | 22 | XYZ | 62 | 652.00
2018-01-16 23:28:56.66738 | Buy | 245 | 24 | XYZ | 86 | 897.00
2018-01-17 23:28:56.66738 | Sell | 150 | 15 | XYZ | 71 | 740.55
2018-01-18 23:28:56.66738 | Buy | 210 | 20 | XYZ | 91 | 950.55
2018-01-19 23:28:56.66738 | Buy | 235 | 22 | XYZ | 113 | 1185.55
2018-01-20 23:28:56.66738 | Sell | 110 | 10 | XYZ | 103 | 1080.63
(8 rows)