sql >> Database >  >> RDS >> Oracle

een Rollup-query met een logisch netwerk met behulp van Oracle SQL

Ik weet dat dit een oude vraag is en niet van nut zal zijn voor de originele poster, maar ik wilde hier een poging toe doen omdat het een interessante vraag was. Ik heb het niet genoeg uitgeprobeerd, dus ik zou verwachten dat dit nog moet worden gecorrigeerd en afgesteld. Maar ik geloof dat de aanpak legitiem is. Ik zou het gebruik van een dergelijke query in een product niet aanbevelen, omdat het moeilijk te onderhouden of te begrijpen zou zijn (en ik geloof niet dat dit echt schaalbaar is). Je zou veel beter af zijn met het maken van een aantal alternatieve datastructuren. Dat gezegd hebbende, heb ik dit uitgevoerd in 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

En het resultaat:

     round | net
    -------+-----
         1 | 780
         2 | 420
    (2 rows)

Om het in stukjes op te splitsen, begon ik met deze dataset:

    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)

De zoekopdracht in de "WITH"-clausule voegt enkele lopende totalen toe aan de tabel.

  • "previous_net_shares" geeft aan hoeveel aandelen beschikbaar zijn om te verkopen vóór het huidige record. Dit vertelt me ​​ook hoeveel 'VERKOOP'-aandelen ik moet overslaan voordat ik het aan deze 'KOOP' kan toewijzen.
  • "previous_sells" is een lopende telling van het aantal gevonden "SELL"-aandelen, dus het verschil tussen twee "previous_sells" geeft het aantal "VERKOOP"-aandelen aan dat in die tijd is gebruikt.

     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)
    

Met deze tabel kunnen we een self-join doen waarbij elk "KOOP"-record is gekoppeld aan elk toekomstig "VERKOOP"-record. Het resultaat ziet er als volgt uit:

    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)

En dan komt het gekke deel dat probeert het aantal beschikbare aandelen te berekenen in de volgorde versus het aantal aandelen dat nog niet is verkocht voor een aankoop. Hier zijn enkele opmerkingen om dat te helpen volgen. De "grootste" oproepen met "0" zeggen alleen dat we geen aandelen kunnen toewijzen als we negatief zijn.

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

Met dank aan David voor zijn hulp




  1. Is er een manier om de MySQL-uitvoeringsvolgorde te forceren?

  2. Hoe voer ik veel SQL-query's uit als transacties?

  3. update als er twee velden zijn, invoegen als dat niet het geval is (MySQL)

  4. Combineer de resultaten van twee niet-gerelateerde zoekopdrachten in één weergave