【问题标题】:What's the most efficient way to match values between 2 tables based on most recent prior date?根据最近的先前日期匹配两个表之间的值的最有效方法是什么?
【发布时间】:2014-05-22 16:34:18
【问题描述】:

我在 MS SQL Server 中有两个表:

dailyt - 包含每日数据:

date             val
---------------------
2014-05-22       10
2014-05-21       9.5
2014-05-20       9
2014-05-19       8
2014-05-18       7.5
etc...

还有periodt - 包含不定期传入的数据:

date             val
---------------------
2014-05-21       2
2014-05-18       1

给定dailyt 中的一行,我想通过将periodt 中的相应值与dailyt 行的日期之前或等于最接近的日期相加来调整其值。所以,输出看起来像:

addt

date             val
---------------------
2014-05-22       12      <- add 2 from 2014-05-21
2014-05-21       11.5    <- add 2 from 2014-05-21
2014-05-20       10      <- add 1 from 2014-05-18
2014-05-19       9       <- add 1 from 2014-05-18
2014-05-18       8.5     <- add 1 from 2014-05-18

我知道这样做的一种方法是在 periodt.date &lt;= dailyt.date 上加入 dailytperiodt 表,然后施加 ROW_NUMBER() (PARTITION BY dailyt.date ORDER BY periodt.date DESC) 条件,然后在行号上添加 WHERE 条件 = 1.

还有其他更有效的方法吗?或者这是非常理想的?

【问题讨论】:

    标签: sql sql-server tsql date


    【解决方案1】:

    我认为使用APPLY 是最有效的方式:

    SELECT  d.Val,
            p.Val,
            NewVal = d.Val + ISNULL(p.Val, 0)
    FROM    Dailyt AS d
            OUTER APPLY
            (   SELECT  TOP 1 Val
                FROM    Periodt p
                WHERE   p.Date <= d.Date
                ORDER BY p.Date DESC
            ) AS p;
    

    Example on SQL Fiddle

    【讨论】:

      【解决方案2】:

      如果periodt 行相对较少,那么有一个选项可能证明非常有效。

      使用子查询或 CTE 将 periodt 转换为 From/To 范围表。 (显然,性能取决于执行此初始步骤的效率,这就是为什么少量 periodt 行更可取的原因。)然后连接到 dailyt 将非常有效。例如

      ;WITH PIds AS (
              SELECT ROW_NUMBER() OVER(ORDER BY PDate) RN, *
              FROM   @periodt
          ),
          PRange AS (
              SELECT  f.PDate AS FromDate, t.PDate as ToDate, f.PVal
              FROM    PIds f
                      LEFT OUTER JOIN PIds t ON
                        t.RN = f.RN + 1
          )
      SELECT  d.*, p.PVal
      FROM    @dailyt d
              LEFT OUTER JOIN PRange p ON
                  d.DDate >= p.FromDate
              AND (d.DDate < p.ToDate OR p.ToDate IS NULL)
      ORDER BY 1 DESC
      

      如果您想尝试查询,以下使用表变量生成示例数据。请注意,我在 dailyt 中添加了一个额外的行,以证明没有日期较小的 periodt 条目。

      DECLARE  @dailyt table (
          DDate date NOT NULL,
          DVal float NOT NULL
      )
      
      INSERT INTO @dailyt(DDate, DVal)
                SELECT '20140522', 10
      UNION ALL SELECT '20140521', 9.5
      UNION ALL SELECT '20140520', 9
      UNION ALL SELECT '20140519', 8
      UNION ALL SELECT '20140518', 7.5
      UNION ALL SELECT '20140517', 6.5
      
      DECLARE @periodt table (
          PDate date NOT NULL,
          PVal int NOT NULL
      )
      
      INSERT INTO @periodt
                SELECT '20140521', 2
      UNION ALL SELECT '20140518', 1
      

      【讨论】:

        猜你喜欢
        • 2019-12-23
        • 1970-01-01
        • 2021-07-30
        • 1970-01-01
        • 1970-01-01
        • 2017-08-10
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多