我有一个表“AuctionResults”,如下所示
Auction Action Shares ProfitperShare
-------------------------------------------
Round1 BUY 6 200
Round2 BUY 5 100
Round2 SELL -2 50
Round3 SELL -5 80
现在我需要在以“先到先得净”为基础的后续轮次中淘汰卖出后,通过每次买入买入来汇总结果
所以在第一轮我买了6股,然后在第二轮中卖出2股,在第三轮中卖出“4”,总净利润为6 * 200-2 * 50-4 * 80 = 780
在第二轮我买了5股并在第3轮卖出“1”(因为之前的“4”属于第1轮),净利润为5 * 100-1 * 80 = 420
...所以结果输出应如下所示:
Auction NetProfit
------------------
Round1 780
Round2 420
我们可以使用Oracle SQL(10g)而不是PL-SQL
来实现这一点提前致谢
答案 0 :(得分:0)
我知道这是一个古老的问题,不会对原版海报有用,但我想对此进行一次尝试,因为这是一个有趣的问题。我没有对它进行足够的测试,所以我希望这仍然需要纠正和调整。但我相信这种方法是合法的。我不建议在产品中使用这样的查询,因为它很难维护或理解(我不相信这是可扩展的)。创建一些备用数据结构会更好。话虽如此,这是我在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_sells”是遇到的“卖出”股数的运行计数,因此两个“previous_sells”之间的差异表示当时使用的“卖出”股票的数量。
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)
然后是疯狂的部分,试图计算订单中可供出售的股票数量与尚未售出的股票数量。以下是一些有助于遵循这一点的说明。 “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
感谢大卫的assistance