sql >> Databasteknik >  >> RDS >> Oracle

en samlad fråga med viss logisk nätning med Oracle SQL

Jag vet att detta är en gammal fråga och inte kommer att vara till nytta för den ursprungliga affischen, men jag ville ta en käft på det här eftersom det var en intressant fråga. Jag testade det inte tillräckligt, så jag förväntar mig att det fortfarande måste korrigeras och justeras. Men jag tror att tillvägagångssättet är legitimt. Jag skulle inte rekommendera att använda en fråga som denna i en produkt eftersom det skulle vara svårt att underhålla eller förstå (och jag tror inte att det är riktigt skalbart). Du skulle vara mycket bättre av att skapa några alternativa datastrukturer. Med det sagt, detta är vad jag körde i 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

Och resultatet:

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

För att dela upp det i bitar började jag med den här datamängden:

    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)

Frågan i "WITH"-satsen lägger till några löpande summor till tabellen.

  • "previous_net_shares" anger hur många aktier som är tillgängliga att sälja före det aktuella rekordet. Detta talar också om för mig hur många "SÄLJ"-andelar jag måste hoppa över innan jag kan börja allokera det till detta "KÖP".
  • "previous_sells" är en löpande räkning av antalet "SELL"-andelar som påträffats, så skillnaden mellan två "previous_sells" indikerar antalet "SELL"-andelar som användes under den tiden.

     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)
    

Med denna tabell kan vi göra en självanslutning där varje "KÖP"-post associeras med varje framtida "SÄLJ"-post. Resultatet skulle se ut så här:

    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)

Och sedan kommer den galna delen som försöker beräkna antalet aktier som är tillgängliga att sälja i ordningen kontra antalet över aktien som ännu inte sålts för ett köp. Här är några anteckningar som hjälper dig att följa det. De "största" samtalen med "0" säger bara att vi inte kan tilldela några aktier om vi är negativa.

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

Tack till David för hans hjälp




  1. Hur konverterar man 1985-02-07T00:00:00.000Z (ISO8601) till ett datumvärde i Oracle?

  2. PHP mysqli_real_escape_string returnerar tom sträng

  3. Vilka kolumner ger generellt bra index?

  4. Oracle till SQL2005 DATETIME-fältet svämmar över i SSIS