2009-12-01 86 views
1

我有一個表「AuctionResults」像下面一個彙總查詢使用Oracle SQL

Auction Action Shares ProfitperShare 
------------------------------------------- 
Round1 BUY  6  200  
Round2 BUY  5  100 
Round2 SELL  -2  50 
Round3 SELL  -5  80 

現在我需要在隨後的幾輪扣除SELLS後聚集通過每年都要購買拍賣結果有一定的邏輯網一個「先到先得淨基礎「

所以在第一回合我買了6股股票,然後在第二回合賣掉了2,第三回合剩下」4「,總淨利潤爲6 * 200-2 * 50-4 * 80 = 780

第二回合我在第三回合買了5股並賣出了「1」(因爲之前的「4」bel onged到ROUND1)與5×100-1×80 = 420

淨利潤......所以得到的輸出應該是這樣的:

Auction NetProfit 
------------------ 
Round1 780  
Round2 420 

我們能做到這一點只使用的Oracle SQL(10克),而不是PL-SQL

在此先感謝

+0

ROUND1,Round2和Round3是序即Round2是ROUND1等以後,你必須在任何一輪後續的網購銷售 – Arun 2009-12-01 18:34:52

+0

我看不出你如何能用當前的設計只使用SQL來完成此任務。您正在嘗試跟蹤大量(買入),但允許在未來幾輪中進行部分批量銷售,但希望在FIFO計算中彙總這些部分批次。例如,第3輪中的賣出-5自身沒有提供任何上下文,其中4股適用於第1輪,其餘部分適用於第2輪。 – tawman 2011-10-07 15:14:06

回答

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_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