历史表上的合并操作

问题描述 投票:0回答:1

我想知道是否存在现有的、完善的算法来对时态表执行合并操作。

作为一个最小的例子,假设我们有一个表 [pricedata]:

+------+------+--------+
| from | to   | price  |
+------+------+--------+
| 2008 | 2009 | 100    |
| 2009 | 2011 | 121    |
| 2011 | 2013 | 142    |
+------+------+--------+

(这里的 [to] 列应该是不包含自身的)。 现在,我们得到一些新数据来覆盖原始数据:

+------+------+--------+
| from | to   | price  |
+------+------+--------+
| 2010 | 2012 | 109    |
+------+------+--------+

预期结果应相应地拆分并重新排列价格:

+------+------+--------+
| from | to   | price  |
+------+------+--------+
| 2008 | 2009 | 100    |
| 2009 | 2010 | 121    |
| 2010 | 2012 | 109    |
| 2012 | 2013 | 142    |
+------+------+--------+

我故意省略了太多细节,因为问题是是否已经有一个重要的资源/算法已经做到了这一点。尽管我的网络搜索没有产生任何结果,但感觉很常见——需要足够的存在。

sql sql-server gaps-and-islands temporal
1个回答
0
投票

对于具有包含开始日期和独占结束日期的数据,重叠日期的测试将是

(A.FromDate < B.ToDate AND B.FromDate < A.ToDate)

在插入新行之前,您可以查询与插入的日期范围重叠的任何现有行,并调整现有的开始和结束日期。

类似:

DECLARE @InsertFrom INT = 2010
DECLARE @InsertTo INT = 2012
DECLARE @InsertPrice INT = 109

UPDATE pricedata
SET
    [from] = CASE WHEN [from] >= @InsertFrom THEN GREATEST([from], @InsertTo) ELSE [from] END,
    [to] = CASE WHEN [to] <= @InsertTo THEN LEAST([to], @InsertFrom) ELSE [to] END
WHERE [from] < @InsertTo
AND @InsertFrom < [to]

INSERT pricedata ([from], [to], price)
VALUES (@InsertFrom, @InsertTo, @InsertPrice)

请注意,如果新的日期范围完全覆盖一个或多个现有日期范围,您最终会得到退化行,其中

to < from
。您可能需要添加另一个语句来删除此类行。 (保留它们可能是无害的,因为检查
from <= lookup < to
的查找永远不会匹配。)

参见这个数据库<>小提琴

© www.soinside.com 2019 - 2024. All rights reserved.