为日期范围选择每个日期并插入

Posted

技术标签:

【中文标题】为日期范围选择每个日期并插入【英文标题】:Select Every Date for Date Range and Insert 【发布时间】:2014-03-22 21:23:25 【问题描述】:

使用 SQL Server 2008 我有一个表 A,其中包含开始日期、结束日期和值。对于表 A 中开始日期和结束日期中的每个日期,我需要在表 B 中插入(或更新,如果已经存在)该日期,以便该表中的值是 A/DateDiff 中的值(Day,StartDate A 的结束日期,A 的结束日期).

例子:

表A

ID    StartDate        EndDate           Value    
1     01 Jan 2014      03 Jan 2014       33
2     01 Feb 2014      02 Feb 2014       20
3     02 Jan 2014      03 Jan 2014       10

表 B

ID    Date            Value
1     01 Jan 2014     11
2     02 Jan 2014     16
3     03 Jan 2014     16
4     01 Feb 2014     10
5     02 Feb 2014     10

计算值的方式是 - 对于 ID 1,有 3 天,这意味着每天 11 个单位。所以 1 月 1 日、2 日、3 日都获得 11 个单位。然后因为还有日期范围为 1 月 2 日至 1 月 3 日的附加单位,即每天 5 个单位,1 月 2 日和 3 日将是 (11+5) 16。2 月 1 日和 2 日只有一个记录,所以它们将只是 20/ 2 = 10。

我可以想到一个使用循环的解决方案,但想完全避免它。 有什么方法可以通过基于集合的解决方案来实现吗?使用基于集合的方法批量执行此操作对我来说很重要。

我正在尝试阅读各种文章,似乎 CTE、日历表或 Tally 表可能会有所帮助,但我看到的示例需要设置变量并传递开始日期和结束日期,我认为这适用于单个记录,但不适用于何时一次做所有的记录。请提出建议。

谢谢!

【问题讨论】:

你的价值观没有意义。他们不应该是 11、16、33、10、20 吗? 计算值的方式是 - 对于 ID 1,有 3 天,这意味着每天 11 个单位。所以 1 月 1 日、2 日、3 日都获得 11 个单位。然后,由于还有日期范围为 1 月 2 日至 1 月 3 日的附加单元,即每天 5 个,1 月 2 日和 3 日将是 16。2 月 1 日和 2 日只有一个记录,所以它们只是 20/2 = 10。跨度> 。 .我很想说你应该删除这个问题并从描述重新开始。 你的意思是在描述中解释计算? 【参考方案1】:

我认为应该这样做 (DEMO):

;with cte as (
  select
     id
    ,startdate
    ,enddate
    ,value / (1+datediff(day, startdate, enddate)) as value
    ,startdate as date
  from units
  union all
  select id, startdate, enddate, value, date+1 as date
  from cte
  where date < enddate
)
select
   row_number() over (order by date) as ID
  ,date
  ,sum(value) as value
from cte
group by date

这个想法是使用递归 CTE 将日期范围分解为每天一条记录。此外,value / (1+datediff(day, startdate, enddate)) 的逻辑将总值平均分布在每个范围内的天数上。最后,我们按天分组,并将当天对应的所有值相加得到输出:

| ID |                            DATE | VALUE |
|----|---------------------------------|-------|
|  1 |  January, 01 2014 00:00:00+0000 |    11 |
|  2 |  January, 02 2014 00:00:00+0000 |    16 |
|  3 |  January, 03 2014 00:00:00+0000 |    16 |
|  4 | February, 01 2014 00:00:00+0000 |    10 |
|  5 | February, 02 2014 00:00:00+0000 |    10 |

从这里您可以按日期加入您的结果表(表 B),并根据需要更新/插入值。该逻辑可能看起来像这样(当然,在生产运行之前先对其进行测试!):

update B set B.VALUE = R.VALUE from TableB B join Result R on B.DATE = R.DATE
insert TableB (DATE, VALUE)
  select DATE, VALUE from Result R where R.DATE not in (select DATE from TableB)

【讨论】:

有一些巧妙的技巧可以解决这个问题(比如使用两个递归 cte,一个分解为 100 天或更短的日期范围,然后第二个完全分解)。范围的最大大小是否有硬性限制?您可以将最大递归深度设置为高于默认值 100 的值。 是的,我想我可以推送默认值。抱歉,我不知道,只是在评论后才意识到,所以删除了该评论。不过谢谢你的回复。 能否请您告知完全取消限制是否有任何危害?

以上是关于为日期范围选择每个日期并插入的主要内容,如果未能解决你的问题,请参考以下文章

反应日期选择器日期范围

如何从 iOS 中两个日期范围内的照片库中获取图像?

EXCEL表里怎么添加日期选择器

按日期范围选择数据并换行

SQL在where语句中使用日期范围的选择子查询来确定该日期范围内的最大值

sql 语句如何插入全年日期?