SQL插值特定日期范围的缺失值-带有某些条件

SQL插值特定日期范围的缺失值-带有某些条件,sql,sql-server,date,time-series,interpolation,Sql,Sql Server,Date,Time Series,Interpolation,网站上也有一些类似的问题,但我相信我的问题可以保证一个新的帖子,因为有一些特定的条件需要合并 我有一个表,每个月一次,结构如下: +----+--------+--------------+--------------+ | ID | amount | interval_beg | interval_end | +----+--------+--------------+--------------+ | 1 | 10 | 12/17/2017 | 1/17/2018 | |

网站上也有一些类似的问题,但我相信我的问题可以保证一个新的帖子,因为有一些特定的条件需要合并

我有一个表,每个月一次,结构如下:

+----+--------+--------------+--------------+
| ID | amount | interval_beg | interval_end |
+----+--------+--------------+--------------+
|  1 |     10 | 12/17/2017   | 1/17/2018    |
|  1 |     10 | 1/18/2018    | 2/18/2018    |
|  1 |     10 | 2/19/2018    | 3/19/2018    |
|  1 |     10 | 3/20/2018    | 4/20/2018    |
|  1 |     10 | 4/21/2018    | 5/21/2018    |
+----+--------+--------------+--------------+
+----+--------+--------------+--------------+
| ID | amount | interval_beg | interval_end |
+----+--------+--------------+--------------+
|  2 |     10 | 10/14/2018   | 11/14/2018   |
|  2 |     10 | 11/15/2018   | 12/15/2018   |
|  2 |     10 | 1/17/2019    | 2/17/2019    |
|  2 |     10 | 2/18/2019    | 3/18/2019    |
|  2 |     10 | 3/19/2019    | 4/19/2019    |
+----+--------+--------------+--------------+
我发现,有时在我知道应该存在数据的年末/年初,有一个月的数据丢失,如下所示:

+----+--------+--------------+--------------+
| ID | amount | interval_beg | interval_end |
+----+--------+--------------+--------------+
|  1 |     10 | 12/17/2017   | 1/17/2018    |
|  1 |     10 | 1/18/2018    | 2/18/2018    |
|  1 |     10 | 2/19/2018    | 3/19/2018    |
|  1 |     10 | 3/20/2018    | 4/20/2018    |
|  1 |     10 | 4/21/2018    | 5/21/2018    |
+----+--------+--------------+--------------+
+----+--------+--------------+--------------+
| ID | amount | interval_beg | interval_end |
+----+--------+--------------+--------------+
|  2 |     10 | 10/14/2018   | 11/14/2018   |
|  2 |     10 | 11/15/2018   | 12/15/2018   |
|  2 |     10 | 1/17/2019    | 2/17/2019    |
|  2 |     10 | 2/18/2019    | 3/18/2019    |
|  2 |     10 | 3/19/2019    | 4/19/2019    |
+----+--------+--------------+--------------+
我需要的是一份声明,该声明将:

  • 确定本年末期间缺失的位置(但不查找缺失的位置 不在年初/年底的月份)
  • 使用现有间隔的长度创建此间隔 该ID(可能使用该ID的平均间隔长度来执行此操作?)。我可以根据上一个间隔和下一个间隔之间的“间隙”创建间隔,但如果我在ID记录的开始或结束处缺少间隔,则该间隔无效(即,如果记录从2015年1月16日开始,我需要2014年12月15日至2015年1月15日的金额)
  • 使用每日平均值为该间隔内插一个“数量” 最近的现有间隔中的“金额”
  • 上述样本的最终结果应如下所示:

    +----+--------+--------------+--------------+
    | ID | amount | interval_beg | interval_end |
    +----+--------+--------------+--------------+
    |  2 |     10 | 10/14/2018   | 11/14/2018   |
    |  2 |     10 | 11/15/2018   | 12/15/2018   |
    |  2 |     10 | 12/16/2018   | 1/16/2018    |
    |  2 |     10 | 1/17/2019    | 2/17/2019    |
    |  2 |     10 | 2/18/2019    | 3/18/2019    |
    +----+--------+--------------+--------------+
    
    “很好拥有”将是一个标志,指示此值是插值的

    有没有一种方法可以在SQL中高效地实现这一点?我已经在SAS中编写了一个解决方案,但需要将其转移到SQL中,而且我的SAS解决方案效率非常低(优化不是目标,所以任何实现我所需的语句都非常好)

    编辑:我在这里用我的示例表制作了一个SQLFIDLE:


    您可以使用一系列CTE来建立缺失期间的数据。在该查询中,第一个CTE(
    EOY
    )生成与表相关的所有年终日期(
    YYYY-12-31
    ),第二个(
    间隔
    )生成每个
    ID
    的平均间隔长度,第三个(
    缺失
    )尝试查找相邻间隔的开始日期(从
    t2
    )和结束日期(从
    t3
    ),以查找任何缺失的日期(由
    t1.ID指示为空)年末间隔。然后在
    INSERT…SELECT
    查询中使用此CTE的输出,将缺少的间隔记录添加到表中,根据需要将间隔长度添加/减去相邻间隔的结束/开始日期,生成缺少的日期

    首先,尽管我们添加了
    interp
    列以指示是否对行进行了插值:

    ALTER TABLE Table1 ADD interp TINYINT NOT NULL DEFAULT 0;
    
    这将所有现有行的
    interp
    设置为
    0
    。然后我们可以执行
    INSERT
    ,将所有这些行的
    interp
    设置为
    1

    WITH EOYS AS (
      SELECT DISTINCT DATEFROMPARTS(DATEPART(YEAR, interval_beg), 12, 31) AS eoy
      FROM Table1
    ),
    INTERVALS AS (
      SELECT ID, AVG(DATEDIFF(DAY, interval_beg, interval_end)) AS interval_len
      FROM Table1
      GROUP BY ID
    ),
    MISSING AS (
      SELECT e.eoy, 
             ids.ID, 
             i.interval_len, 
             COALESCE(t2.amount, t3.amount) AS amount, 
             DATEADD(DAY,  1, t2.interval_end) AS interval_beg, 
             DATEADD(DAY, -1, t3.interval_beg) AS interval_end
      FROM EOYS e
      CROSS JOIN (SELECT DISTINCT ID FROM Table1) ids
      JOIN INTERVALS i ON i.ID = ids.ID
      LEFT JOIN Table1 t1 ON ids.ID = t1.ID
                         AND e.eoy BETWEEN t1.interval_beg AND t1.interval_end
      LEFT JOIN Table1 t2 ON ids.ID = t2.ID
                         AND DATEADD(MONTH, -1, e.eoy) BETWEEN t2.interval_beg AND t2.interval_end
      LEFT JOIN Table1 t3 ON ids.ID = t3.ID
                         AND DATEADD(MONTH,  1, e.eoy) BETWEEN t3.interval_beg AND t3.interval_end
      WHERE t1.ID IS NULL
    )
    INSERT INTO Table1 (ID, amount, interval_beg, interval_end, interp)
    SELECT ID,
           amount,
           COALESCE(interval_beg, DATEADD(DAY, -interval_len, interval_end)) AS interval_beg,
           COALESCE(interval_end, DATEADD(DAY,  interval_len, interval_beg)) AS interval_end,
           1 AS interp
    FROM MISSING
    
    这会将以下行添加到表中:

    ID  amount  interval_beg    interval_end    interp
    2   10      2017-12-05      2018-01-04      1
    2   10      2018-12-16      2019-01-16      1
    2   10      2019-12-28      2020-01-27      1
    

    < P> < /P>请标记一个DBMS(Oracle,MySQL等)。任何答案都需要特定于SQL的特定方言。-但是,考虑应用程序代码中的数据显示问题。谢谢!我可能措辞不正确,因为我对SQL不太熟悉(因此,我在请求一个非常简单的程序的解决方案)。。我不需要仅仅从数据库中查询,我想写入表,以便将这些信息存储在数据库中。我希望有一个标志,以便可以轻松返回并确定哪些值是插值的,哪些是“原始的”。您的fiddle是MySQL,但问题标记为SQL server。是哪一个?fiddle中的示例数据的预期输出是什么?@AlJones1816您的fiddle中的数据比您的问题多得多。我只是想弄清楚您希望为fiddle中的数据生成查询的间隔。这太棒了,非常感谢!你的描述非常清楚,我能够理解并从中学习。感谢你耐心等待,因为我还是一个新手,并且学习了正确的礼仪。@Aljones 1816别担心,我很高兴能帮上忙。