【问题标题】:SQL Server RankingSQL Server 排名
【发布时间】:2018-04-26 15:28:31
【问题描述】:

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

这是我的数据集示例:

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 天的 QuoteClose 进行排名。

例如:

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,在 2018 年 4 月 12 日,我比较 4/6/8-4/12/8 的 Quoteclose 以确定排名为 1。

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

然后循环将窗口向前移动 1 天,并找到 2018 年 4 月 13 日的排名,这将是 2。对该股票重复该过程,然后对表中的所有其他股票重复该过程。

我的计划很复杂,但应该可以完成工作。

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

我试图让这个过程成为一个动态的过程,这样我就可以生成不同的排名周期:7 天、20 天等。

【问题讨论】:

    标签: sql-server sql-server-2012 ranking


    【解决方案1】:

    把它分成几个步骤:

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

    【讨论】:

    • 我正在尝试将输出插入到一个新表中,但是最后一个 WHERE 语句有问题,有什么建议吗?
    • 您是否收到错误消息?如果您只是在最后一个 SELECT 语句之前放置一个 INSERT INTO (即将 SELECT 语句的结果插入表中),它应该可以工作。或者在 SELECT 中添加 INTO 子句并将其写入新表。
    【解决方案2】:

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

    【讨论】:

    • 我建议使用较小的 @dayInRank 值进行测试,以真正了解此查询的工作原理
    猜你喜欢
    • 2018-09-23
    • 1970-01-01
    • 2020-11-21
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多