SQL 服务器排名

SQL Server Ranking

我有 table 只股票,我想为每只股票创建滚动排名。

这是我的数据集示例:

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

每一天,我都想对前 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 天的数据。

例如,对于 2018 年 4 月 12 日的股票 #47,我正在比较 4/6/8-4/12/8 的 Quoteclose 以确定排名为 1。

然后我将该排名保存到另一个 table。

循环然后将 window 向前移动 1 天,并找到 2018 年 4 月 13 日的排名,这将是 2。对这只股票重复该过程,然后对 table.

我的计划很复杂,但应该能完成。

是否有更好更简洁的方法来实现所有股票的滚动排名?

我正在努力使它成为一个动态过程,以便我可以生成不同的排名周期:7 天、20 天等。

我不确定我是否理解你的排名,但我假设它是从最好(最大)到最差(最小)排名的 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

将其分解为以下步骤:

首先 (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