我知道這是一個老問題並不會使用到原來的海報,但我想花刺在這一點,因爲這是一個有趣題。我沒有對它進行足夠的測試,所以我預計這還需要進行修正和調整。但我相信這種方法是合法的。我不建議在產品中使用這樣的查詢,因爲這很難維護或理解(並且我不認爲這是真正可擴展的)。創建一些備用數據結構會更好。話說回來,這是我在PostgreSQL 9.1跑:
WITH x AS (
SELECT round, action
,ABS(shares) AS shares
,profitpershare
,COALESCE(SUM(shares) OVER(ORDER BY round, action
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING)
, 0) AS previous_net_shares
,COALESCE(ABS(SUM(CASE WHEN action = 'SELL' THEN shares ELSE 0 END)
OVER(ORDER BY round, action
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING)), 0) AS previous_sells
FROM AuctionResults
ORDER BY 1,2
)
SELECT round, shares * profitpershare - deduction AS net
FROM (
SELECT buy.round, buy.shares, buy.profitpershare
,SUM(LEAST(LEAST(sell.shares, GREATEST(buy.shares - (sell.previous_sells - buy.previous_sells), 0)
,GREATEST(sell.shares + (sell.previous_sells - buy.previous_sells) - buy.previous_net_shares, 0)
)
) * sell.profitpershare) AS deduction
FROM x buy
,x sell
WHERE sell.round > buy.round
AND buy.action = 'BUY'
AND sell.action = 'SELL'
GROUP BY buy.round, buy.shares, buy.profitpershare
) AS y
而結果:
round | net
-------+-----
1 | 780
2 | 420
(2 rows)
把它分解成塊,我開始與這組數據:
CREATE TABLE AuctionResults(round int, action varchar(4), shares int, profitpershare int);
INSERT INTO AuctionResults VALUES(1, 'BUY', 6, 200);
INSERT INTO AuctionResults VALUES(2, 'BUY', 5, 100);
INSERT INTO AuctionResults VALUES(2, 'SELL',-2, 50);
INSERT INTO AuctionResults VALUES(3, 'SELL',-5, 80);
INSERT INTO AuctionResults VALUES(4, 'SELL', -4, 150);
select * from auctionresults;
round | action | shares | profitpershare
-------+--------+--------+----------------
1 | BUY | 6 | 200
2 | BUY | 5 | 100
2 | SELL | -2 | 50
3 | SELL | -5 | 80
4 | SELL | -4 | 150
(5 rows)
「WITH」子句中的查詢將一些運行總計添加到表中。
- 「previous_net_shares」表示在當前記錄之前有多少股可以賣出。這也告訴我在我開始分配給這個'買入'之前,我需要跳過多少'賣出'股票。
「previous_sells」是遇到的「SELL」份額數的運行計數,所以兩個「previous_sells」之間的差值表示當時使用的'SELL'份額的數量。
round | action | shares | profitpershare | previous_net_shares | previous_sells
-------+--------+--------+----------------+---------------------+----------------
1 | BUY | 6 | 200 | 0 | 0
2 | BUY | 5 | 100 | 6 | 0
2 | SELL | 2 | 50 | 11 | 0
3 | SELL | 5 | 80 | 9 | 2
4 | SELL | 4 | 150 | 4 | 7
(5 rows)
有了這張表,我們可以做一個自連接,其中每個「買入」的記錄與每個未來的「沽售」記錄相關聯。其結果是這樣的:
SELECT buy.round, buy.shares, buy.profitpershare
,sell.round AS sellRound, sell.shares AS sellShares, sell.profitpershare AS sellProfitpershare
FROM x buy
,x sell
WHERE sell.round > buy.round
AND buy.action = 'BUY'
AND sell.action = 'SELL'
round | shares | profitpershare | sellround | sellshares | sellprofitpershare
-------+--------+----------------+-----------+------------+--------------------
1 | 6 | 200 | 2 | 2 | 50
1 | 6 | 200 | 3 | 5 | 80
1 | 6 | 200 | 4 | 4 | 150
2 | 5 | 100 | 3 | 5 | 80
2 | 5 | 100 | 4 | 4 | 150
(5 rows)
然後就是試圖來計算的可供選擇以出售VS尚未出售尚未對買入過股票數量股份數量瘋狂的一部分。以下是一些幫助解決這個問題的註釋。以「0」表示的「最大」電話只是表示如果我們處於否定狀態,我們不能分配任何股票。
-- allocated sells
sell.previous_sells - buy.previous_sells
-- shares yet to sell for this buy, if < 0 then 0
GREATEST(buy.shares - (sell.previous_sells - buy.previous_sells), 0)
-- number of sell shares that need to be skipped
buy.previous_net_shares
感謝David他assistance
ROUND1,Round2和Round3是序即Round2是ROUND1等以後,你必須在任何一輪後續的網購銷售 – Arun 2009-12-01 18:34:52
我看不出你如何能用當前的設計只使用SQL來完成此任務。您正在嘗試跟蹤大量(買入),但允許在未來幾輪中進行部分批量銷售,但希望在FIFO計算中彙總這些部分批次。例如,第3輪中的賣出-5自身沒有提供任何上下文,其中4股適用於第1輪,其餘部分適用於第2輪。 – tawman 2011-10-07 15:14:06