【问题标题】:Select top and bottom 3 records by date for a variety of dates按日期为各种日期选择顶部和底部 3 条记录
【发布时间】:2012-11-26 23:03:49
【问题描述】:

我有一张汇率表,其格式类似于以下内容:

asofdate    currency    spot    fwd1m   fwdyield    rank_
1999-03-26 00:00:00.000 EUR 0.93161900  0.93340000  1.001911725716199433459 1
1999-03-26 00:00:00.000 NOK 7.80300000  7.81630000  1.001704472638728694092 2
1999-03-26 00:00:00.000 CAD 1.51350000  1.51355000  1.000033036009250082590 3
1999-03-26 00:00:00.000 AUD 1.57728700  1.57713800  0.999905533996032427833 4
1999-03-26 00:00:00.000 NZD 1.86828600  1.86748300  0.999570194285029165770 5
1999-03-26 00:00:00.000 GBP 0.61728400  0.61665000  0.998972920082166393426 6
1999-03-26 00:00:00.000 SEK 8.33400000  8.32080000  0.998416126709863210943 7
1999-03-26 00:00:00.000 CHF 1.48480000  1.48007000  0.996814385775862068965 8
1999-03-26 00:00:00.000 JPY 120.09000000    119.60550000    0.995965525855608293779 9
1999-05-26 00:00:00.000 EUR 0.95438100  0.95662000  1.002346023233907632276 1
1999-05-26 00:00:00.000 NOK 7.85100000  7.86505000  1.001789580945102534708 2
1999-05-26 00:00:00.000 AUD 1.54154500  1.54147300  0.999953293611279592875 3
1999-05-26 00:00:00.000 CAD 1.47330000  1.47307000  0.999843887870766306930 4

从这个表中,我想保留每个日期的排名(基于 fwdyield 字段)的 TOP 和 BOTTOM 3 记录。

输出看起来像这样,但会包括初始表中存在的每个日期:

asofdate    currency    spot    fwd1m   fwdyield    pos
1999-03-26 00:00:00.000 JPY 120.09000000    119.60550000    0.995965525855608293779 -1
1999-03-26 00:00:00.000 CHF 1.48480000  1.48007000  0.996814385775862068965 -1
1999-03-26 00:00:00.000 SEK 8.33400000  8.32080000  0.998416126709863210943 -1
1999-03-26 00:00:00.000 CAD 1.51350000  1.51355000  1.000033036009250082590 1
1999-03-26 00:00:00.000 NOK 7.80300000  7.81630000  1.001704472638728694092 1
1999-03-26 00:00:00.000 EUR 0.93161900  0.93340000  1.001911725716199433459 1

挑战在于为每个日期执行此操作,以避免需要使用循环/光标。想法?

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    这可以通过使用一些 OLAP 函数来完成:

    SELECT * -- only for the example, because I don't know what you need
    FROM (SELECT a.*, ROW_NUMBER() OVER(PARTITION BY CAST(asOfDate as DATE) 
                                        ORDER BY fwdyield ASC) as ascRank,
                      ROW_NUMBER() OVER(PARTITION BY CAST(asOfDate as DATE) 
                                        ORDER BY fwdyield DESC) as descRank
          FROM Exchange a) b
    WHERE ascRank < 4
          OR descRank < 4
    

    从您的示例数据中产生以下结果:

    ASOFDATE    CURRENCY    SPOT    FWD1M   FWDYIELD    RANK    ASCRANK DESCRANK
    March, 26 1999 00:00:00+0000    EUR 0.931618988514  0.9333999753    1.001911759377  1   9   1
    March, 26 1999 00:00:00+0000    NOK 7.802999973297  7.816299915314  1.001704454422  2   8   2
    March, 26 1999 00:00:00+0000    CAD 1.513499975204  1.513550043106  1.000033020973  3   7   3
    March, 26 1999 00:00:00+0000    SEK 8.333999633789  8.320799827576  0.998416125774  7   3   7
    March, 26 1999 00:00:00+0000    CHF 1.484799981117  1.480069994926  0.996814370155  8   2   8
    March, 26 1999 00:00:00+0000    JPY 120.089996337891    119.605499267578    0.995965540409  9   1   9
    May, 26 1999 00:00:00+0000  EUR 0.954380989075  0.956619977951  1.002346038818  1   4   1
    May, 26 1999 00:00:00+0000  NOK 7.850999832153  7.86504983902   1.001789569855  2   3   2
    May, 26 1999 00:00:00+0000  AUD 1.541545033455  1.541473031044  0.999953269958  3   2   3
    May, 26 1999 00:00:00+0000  CAD 1.473299980164  1.473070025444  0.999843895435  4   1   4
    

    (工作SQL Fiddle example

    不过这里有几个问题:

    • 因为asOfDate 是一个时间戳(一个SQL Server DATETIMEDATETIME2),它需要被转换/转换。这意味着它(可能)将无法使用索引。我假设这应该是“工作日”(或类似的),因此将其转换为 DATE 类型应该没问题(出于“域”原因,也许无论如何都应该这样做)。
    • 您的列名有点神秘……fwd... 代表什么?

    (作为旁注,我注意到原始的 rank 列与 descRank 匹配 - 如果这已经存储,您显然可以删除那个特定的计算列。)

    【讨论】:

    • 请注意在 SQL Server this doesn't mean what you think it means 中使用术语 timestamp。同样在 2008 年以后,您可以在许多情况下转换为 date 而不会失去 sargability(但我尚未测试这是否是其中一种情况)。
    • @AaronBertrand - 啊,谢谢。在 DB2 中,类型为TIMESTAMP,一般情况下我对 SQL Server 的操作不多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2020-12-16
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 2021-02-11
    相关资源
    最近更新 更多