Каков наилучший способ кодирования этого коррелированного запроса? (Выберите цены, которые могут содержать NULL в соответствии с приоритетом) - PullRequest
3 голосов
/ 28 сентября 2011

Предположим, у вас есть портфель для оценки стоимости, содержащий 4 актива, которые должны быть оценены. SourceID определяет приоритет, который должен быть предоставлен PriceSource, и должен быть получен самый низкий SourceID. Если в таблице EODPrice нет цены, следует извлечь AverageBookCost (который находится в другой таблице). Я использую SQL Server 2005.

В качестве примера, давайте представим, что таблица EODPrice содержит следующие данные (отсутствует 'TEST004'):

SourceID    Date                   Ticker     Price
0           2011-08-02 00:00:00    TEST001    104.50
1           2011-08-01 00:00:00    TEST001    100.00
1           2011-08-02 00:00:00    TEST001    105.00
1           2011-08-04 00:00:00    TEST001    115.00
2           2011-08-03 00:00:00    TEST001    109.38
2           2011-08-04 00:00:00    TEST001    114.24
1           2011-08-01 00:00:00    TEST002    9.99
1           2011-08-02 00:00:00    TEST002    9.89
1           2011-08-03 00:00:00    TEST002    9.79
1           2011-08-04 00:00:00    TEST002    9.69
0           2011-08-03 00:00:00    TEST003    0.42
2           2011-08-01 00:00:00    TEST003    0.33
2           2011-08-02 00:00:00    TEST003    0.38
2           2011-08-03 00:00:00    TEST003    0.28
2           2011-08-04 00:00:00    TEST003    0.45

Давайте представим, что мы хотели бы создать оператор Select, в котором мы получаем EODPrice для следующих активов ('TEST001', 'TEST002', 'TEST003', 'TEST004'). Обратите внимание, что «TEST004» - это новый актив, который только что попал на рынок, и в таблице EODPrice или на рынке еще нет цены.

Далее, давайте представим, что ВСЕ тикеры для любой даты имеют поле NULL AverageBookCost, отличное от NULL, из таблицы RunningTotal. (т. е. SELECT AverageBookCost FROM RunningTotal WHERE Ticker = 'TEST004' И Date = '2011-08-03' вернет значение 0,15).

Как мне построить наиболее эффективный запрос 'Correlated' или 'COALESCE / ISNULL':

SELECT Ticker, SourceID, Price
   ???
   WHERE [Date] = '2011-08-03' 
   AND [Ticker] IN ('TEST001','TEST002', 'TEST003' and 'TEST004') 

Это вернет следующую таблицу: (Обратите внимание, что цена 'TEST004' представляет собой AverageBookCost, а не таблицу EODPrice, тогда для SourceID задано значение NULL, указывающее, что цена указана в таблице RunningTotal:

Ticker   SourceID   Price
TEST1    2          109.38
TEST2    1          9.79
TEST3    0          0.42
TEST4    NULL       0.15

Большое спасибо, Берти.

1 Ответ

2 голосов
/ 28 сентября 2011

Скорее всего, я слишком усложнил, но это может помочь вам начать.

В двух словах, рассуждение выглядит так

  • В подпункте SELECT все тикеры на данную дату с самым низким SourceID.
  • JOIN Результаты этого подпункта возвращаются с исходной таблицей. Этот шаг позволяет получить цену для каждого тикера с указанной датой и самым низким SourceID.
  • FULL OUTER JOIN предыдущий результат со средней стоимостью книги. Этот шаг добавляет к каждой строке среднюю цену для этого тикера и добавляет строки для тикеров, у которых нет записи, возвращенной из Pricetable.
  • SELECT из этих результатов указана цена, если она доступна, в противном случае выберите из добавленных столбцов среднюю стоимость книги.

Оператор SQL

SELECT  [Ticker] = ISNULL(pt.Ticker, pt_avg.Ticker)
        , [SourceID] = pt.SourceID
        , [Price] = ISNULL(pt.Price, pt_avg.AverageBookCost)
FROM    EODPriceTable pt 
        INNER JOIN (
          SELECT  SourceID = MIN(SourceID), Ticker, Date
          FROM    EODPriceTable
          WHERE   Date = '2011-08-03 00:00:00'
          GROUP BY
                  Ticker, Date
         ) pt_min ON  pt_min.SourceID = pt.SourceID 
                      AND pt_min.Ticker = pt.Ticker
                      AND pt_min.Date = pt.Date
         FULL OUTER JOIN (
            SELECT  Ticker, AverageBookCost
            FROM    RunningTable
         ) pt_avg ON pt_avg.Ticker = pt.Ticker
WHERE  ISNULL(pt.Ticker, pt_avg.Ticker) IN ('TEST001', 'TEST002', 'TEST003', 'TEST004')

Тестовый скрипт

;WITH EODPriceTable (SourceID, Date, Ticker, Price) AS (
  SELECT 0, '2011-08-02 00:00:00', 'TEST001', 104.50
  UNION ALL SELECT 1, '2011-08-01 00:00:00', 'TEST001', 100.00
  UNION ALL SELECT 1, '2011-08-02 00:00:00', 'TEST001', 105.00
  UNION ALL SELECT 1, '2011-08-04 00:00:00', 'TEST001', 115.00
  UNION ALL SELECT 2, '2011-08-03 00:00:00', 'TEST001', 109.38
  UNION ALL SELECT 2, '2011-08-04 00:00:00', 'TEST001', 114.24
  UNION ALL SELECT 1, '2011-08-01 00:00:00', 'TEST002', 9.99
  UNION ALL SELECT 1, '2011-08-02 00:00:00', 'TEST002', 9.89
  UNION ALL SELECT 1, '2011-08-03 00:00:00', 'TEST002', 9.79
  UNION ALL SELECT 1, '2011-08-04 00:00:00', 'TEST002', 9.69
  UNION ALL SELECT 0, '2011-08-03 00:00:00', 'TEST003', 0.42
  UNION ALL SELECT 2, '2011-08-01 00:00:00', 'TEST003', 0.33
  UNION ALL SELECT 2, '2011-08-02 00:00:00', 'TEST003', 0.38
  UNION ALL SELECT 2, '2011-08-03 00:00:00', 'TEST003', 0.28
  UNION ALL SELECT 2, '2011-08-04 00:00:00', 'TEST003', 0.45
)
, RunningTable (Ticker, AverageBookCost) AS (
  SELECT 'TEST004', 0.15
  UNION ALL SELECT 'TEST003', 0.09
)
SELECT  [Ticker] = ISNULL(pt.Ticker, pt_avg.Ticker)
        , [SourceID] = pt.SourceID
        , [Price] = ISNULL(pt.Price, pt_avg.AverageBookCost)
FROM    EODPriceTable pt 
        INNER JOIN (
          SELECT  SourceID = MIN(SourceID), Ticker, Date
          FROM    EODPriceTable
          WHERE   Date = '2011-08-03 00:00:00'
          GROUP BY
                  Ticker, Date
         ) pt_min ON  pt_min.SourceID = pt.SourceID 
                      AND pt_min.Ticker = pt.Ticker
                      AND pt_min.Date = pt.Date
         FULL OUTER JOIN (
            SELECT  Ticker, AverageBookCost
            FROM    RunningTable
         ) pt_avg ON pt_avg.Ticker = pt.Ticker
WHERE  ISNULL(pt.Ticker, pt_avg.Ticker) IN ('TEST001', 'TEST002', 'TEST003', 'TEST004')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...