Рейтинг SQL Server - PullRequest
       5

Рейтинг SQL Server

0 голосов
/ 26 апреля 2018

У меня есть таблица акций, которую я хотел бы создать для каждого запаса.

Вот образец моего набора данных:

StockID QuoteID QuoteDay    QuoteClose
47      230     2018-04-06  5.1200
47      231     2018-04-07  5.2100
47      232     2018-04-08  5.3000
47      233     2018-04-09  5.2100
47      234     2018-04-10  5.1900
47      235     2018-04-11  5.5200
47      236     2018-04-12  7.1600
47      237     2018-04-13  6.6900
47      238     2018-04-14  6.6300
47      239     2018-04-15  7.0200
47      240     2018-04-16  6.6300
47      241     2018-04-17  6.5800
251     100     2018-04-06  0.1906
251     101     2018-04-07  0.1969
251     102     2018-04-08  0.1986
251     103     2018-04-09  0.2291
251     104     2018-04-10  0.1963
251     105     2018-04-11  0.1995
251     106     2018-04-12  0.2271
251     107     2018-04-13  0.3722
251     108     2018-04-14  0.3073
251     109     2018-04-15  0.3292
251     110     2018-04-16  0.2905
251     111     2018-04-17  0.2784

Каждый день я хочу ранжировать QuoteClose в течение предыдущих 6 дней.

Например:

StockID QuoteID QuoteDay    QuoteClose  7d Rank
47      230     04/06/18     5.1200     
47      231     04/07/18     5.2100     
47      232     04/08/18     5.3000     
47      233     04/09/18     5.2100     
47      234     04/10/18     5.1900     
47      235     04/11/18     5.5200     
47      236     04/12/18     7.1600       1
47      237     04/13/18     6.6900       2
47      238     04/14/18     6.6300       3
47      239     04/15/18     7.0200       2
47      240     04/16/18     6.6300       4
47      241     04/17/18     6.5800       6
251     100     04/06/18     0.1906     
251     101     04/07/18     0.1969     
251     102     04/08/18     0.1986     
251     103     04/09/18     0.2291     
251     104     04/10/18     0.1963     
251     105     04/11/18     0.1995     
251     106     04/12/18     0.2271       2
251     107     04/13/18     0.3722       1
251     108     04/14/18     0.3073       2
251     109     04/15/18     0.3292       2
251     110     04/16/18     0.2905       4
251     111     04/17/18     0.2784       5

Обратите внимание, что первые 6 дней не имеют рейтинга.

У меня проблемы с объединением ранга с номером строки, поэтому мой подход состоит в том, чтобы иметь цикл, который подает только 7 дней данных за раз для каждой акции.

Например, для акции № 47, 4/12/18, я сравниваю Quoteclose от 4/6 / 8-4 / 12/8, чтобы определить, что рейтинг будет 1.

Затем я сохраняю этот рейтинг в другой таблице.

Затем цикл сместит окно вперед на 1 день и найдет ранжирование для 13.04.18, равное 2. Процесс повторяется для этой акции, а затем для всех других акций в таблице.

Мой план запутан, но работа должна быть выполнена.

Существуют ли лучшие и более чистые способы достижения этого скользящего ранга для всех акций?

Я пытаюсь сделать этот процесс динамичным, чтобы я мог генерировать разные периоды ранжирования: 7-дневный, 20-дневный и т. Д.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Разбивая это на шаги:

Сначала ( OrderedRankSets CTE) получают набор строк для каждого StockID и QuoteDay, которые включают в себя текущую строку и все предыдущие строки, пронумерованные по убыванию в QuoteDay. Позже мы можем использовать эту нумерацию для ограничения предыдущих строк, которые мы собираемся ранжировать.

Второй ( RankedQuoteDays CTE), ранжируйте каждый из этих наборов котировок, где у нас фактически есть по крайней мере количество строк в периоде для каждого дня котировки, и включайте только строки до длины периода.

Наконец, нам не нужно выводить все строки для наборов, нам просто нужен самый последний для каждого дня котировки (день котировки = предыдущий день котировки), поэтому в конечном запросе это просто выводит (см. SQL) Fiddle )

DECLARE @Period INT = 7;

WITH 
    OrderedRankSets AS (
       SELECT
            Quotes.StockID
        ,   Quotes.QuoteID
        ,   Quotes.QuoteDay
        ,   PriorQuotes.QuoteDay AS PriorQuoteDay
        ,   PriorQuotes.QuoteClose
        ,   ROW_NUMBER() OVER (PARTITION BY Quotes.StockID, Quotes.QuoteDay ORDER BY PriorQuotes.QuoteDay DESC) AS RowNumber
        ,   COUNT(*) OVER (PARTITION BY Quotes.StockID, Quotes.QuoteDay) AS [RowCount]
        FROM 
            Quotes
        JOIN Quotes AS PriorQuotes ON (PriorQuotes.StockID = Quotes.StockID
                                       AND PriorQuotes.QuoteDay <= Quotes.QuoteDay)
    )
,  RankedQuoteDays AS (
       SELECT 
          OrderedRankSets.*
       ,  CASE WHEN [RowCount] < @Period THEN NULL ELSE RANK() OVER (PARTITION BY StockID, QuoteDay ORDER BY QuoteClose DESC) END AS QuoteRank
       FROM
          OrderedRankSets
       WHERE
          RowNumber <= @Period
   )
SELECT
    RankedQuoteDays.StockID
,   RankedQuoteDays.QuoteID
,   RankedQuoteDays.QuoteDay
,   RankedQuoteDays.QuoteClose
,   RankedQuoteDays.QuoteRank
FROM
    RankedQuoteDays
WHERE
    QuoteDay = PriorQuoteDay
ORDER BY
    StockID, QuoteDay
0 голосов
/ 26 апреля 2018

Я не уверен, что понимаю ваш рейтинг, но я предполагаю, что это скользящее среднее значение 7 (переменный день), ранжированное от лучшего (наибольшее число) до худшего (самое маленькое)

declare  @t table (
StockID int,    QuoteID int,    QuoteDay date,  QuoteClose money)
insert into @t
values
    (47,230,'20180406',5.12)
,   (47,231,'20180407',5.21)
,   (47,232,'20180408',5.3)
,   (47,233,'20180409',5.21)
,   (47,234,'20180410',5.19)
,   (47,235,'20180411',5.52)
,   (47,236,'20180412',7.16)
,   (47,237,'20180413',6.69)
,   (47,238,'20180414',6.63)
,   (47,239,'20180415',7.02)
,   (47,240,'20180416',6.63)
,   (47,241,'20180417',6.58)
,   (251,100,'20180406',0.1906)
,   (251,101,'20180407',0.1969)
,   (251,102,'20180408',0.1986)
,   (251,103,'20180409',0.2291)
,   (251,104,'20180410',0.1963)
,   (251,105,'20180411',0.1995)
,   (251,106,'20180412',0.2271)
,   (251,107,'20180413',0.3722)
,   (251,108,'20180414',0.3073)
,   (251,109,'20180415',0.3292)
,   (251,110,'20180416',0.2905)
,   (251,111,'20180417',0.2784)

declare @dayInRank int = 7


;with cte as
(
    select rn=row_number()over(partition by StockID order by QuoteDay)
        ,*
    from @t
)

,RollingAvg as
(
    select StockID,QuoteDay,RollingAvg=s.RollingSum/@dayInRank
    from cte
        cross apply (select SUM(QuoteClose) from cte c2 where cte.StockID=c2.StockID and c2.rn between cte.rn-(@dayInRank-1) and cte.rn) s(RollingSum) 
    where rn>=@dayInRank
)

select *,Rank=Row_Number()over (partition by StockID order by ra.RollingAvg desc)
from RollingAvg ra
order by StockID,QuoteDay
...