Oracle
 sql >> база данни >  >> RDS >> Oracle

сборна заявка с някакво логическо нетиране с помощта на Oracle SQL

Знам, че това е стар въпрос и няма да е от полза за оригиналния плакат, но исках да се сблъскам с него, защото беше интересен въпрос. Не го тествах достатъчно, така че бих очаквал, че това все още трябва да бъде коригирано и настроено. Но смятам, че подходът е легитимен. Не бих препоръчал използването на заявка като тази в продукт, защото би било трудно да се поддържа или разбира (и не вярвам, че това е наистина мащабируемо). Ще бъде много по-добре да създадете някои алтернативни структури от данни. Като казах това, това е, което пуснах в 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)

И тогава идва лудата част, която се опитва да изчисли броя на наличните за продажба акции в поръчката спрямо броя над акциите, които все още не са продадени за покупка. Ето някои бележки, за да ви помогнем да следвате това. „Най-големите“ обаждания с „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

Благодаря на Дейвид за неговия помощ




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Не разбирам защо моят SQL не работи

  2. Предайте обект от тип таблица като входен параметър към съхранена процедура в Oracle от C#

  3. арабският знак не е вмъкнат правилно (като ????) в базата данни на Oracle?

  4. Как да върна няколко реда чрез pl/sql съхранена функция?

  5. Как да дефинирате първичен ключ за автоматично увеличение в Oracle