sql >> Base de Datos >  >> RDS >> Oracle

una consulta de resumen con algunas redes lógicas utilizando Oracle SQL

Sé que esta es una pregunta antigua y no será útil para el póster original, pero quería intentarlo porque era una pregunta interesante. No lo probé lo suficiente, por lo que esperaría que esto todavía deba corregirse y ajustarse. Pero creo que el enfoque es legítimo. No recomendaría usar una consulta como esta en un producto porque sería difícil de mantener o comprender (y no creo que esto sea realmente escalable). Sería mucho mejor crear algunas estructuras de datos alternativas. Habiendo dicho eso, esto es lo que ejecuté en 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

Y el resultado:

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

Para dividirlo en partes, comencé con este conjunto de datos:

    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)

La consulta en la cláusula "CON" agrega algunos totales acumulados a la tabla.

  • "previous_net_shares" indica cuántas acciones están disponibles para vender antes del registro actual. Esto también me dice cuántas acciones de 'VENDER' debo omitir antes de poder comenzar a asignarlas a esta 'COMPRA'.
  • "previous_sells" es un conteo continuo de la cantidad de acciones "SELL" encontradas, por lo que la diferencia entre dos "previous_sells" indica la cantidad de acciones "SELL" utilizadas en ese momento.

     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)
    

Con esta tabla, podemos hacer una autounión donde cada registro de "COMPRAR" se asocia con cada registro futuro de "VENDER". El resultado se vería así:

    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)

Y luego viene la parte loca que trata de calcular el número de acciones disponibles para vender en la orden frente al número de acciones que aún no se han vendido para una compra. Aquí hay algunas notas para ayudar a seguir eso. Las llamadas "más grandes" con "0" solo dicen que no podemos asignar acciones si estamos en negativo.

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

Gracias a David por su asistencia