提问人:George Menoutis 提问时间:10/31/2023 最后编辑:George Menoutis 更新时间:10/31/2023 访问量:79
历史表上的合并操作
Merge operations on historic table
问:
我想知道是否存在一种成熟的算法来对时态表执行合并操作。
举个最小的例子,假设我们有一个表 [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 |
+------+------+--------+
我故意省略了太多细节,因为问题是是否已经有一个重要的资源/算法已经这样做了。感觉很普遍,需要在身边,尽管我的网络搜索没有产生任何东西。
答:
1赞
T N
10/31/2023
#1
注意:此答案已对原始帖子进行了重大修改,以正确处理需要拆分的重叠情况。
我不确定是否有一个成熟的(众所周知的)算法,但我相信以下内容可能包括您正在寻找的逻辑。
对于具有包含开始日期和独占结束日期的数据,重叠日期的检验为 。(A.FromDate < B.ToDate AND B.FromDate < A.ToDate)
在插入新行之前,您可以查询与要插入的日期范围重叠的任何现有行,并调整现有的开始日期和结束日期。这些都需要调整、拆分甚至删除,以消除重叠。
- 如果新范围与现有行的下限重叠,则应调整现有行的值。
from
- 如果新范围与现有行的上限重叠,则应调整现有行的值。
to
- 如果新范围完全包含在现有行的范围内,则需要复制和调整该现有行,以覆盖未被新插入所取代的剩余下限和上限范围。
- 如果任何现有行完全包含在要插入的新范围内,则这些行可能会被删除。
我假设新数据总是会取代具有重叠范围的现有数据,并且完全被取代的行可能会被删除。
以下逻辑将处理上述所有情况:
-- Delete any row completely superseded by new insert
DELETE pricedata
WHERE [from] >= @InsertFrom
AND [to] <= @InsertTo
-- Duplicate and adjust any row split by new insert, leaving lower residual
INSERT pricedata ([from], [to], price)
SELECT [from], @InsertFrom, price
FROM pricedata
WHERE [from] < @InsertFrom
AND [to] > @InsertTo
-- Adjust original row split by new insert, leaving upper residual
UPDATE pricedata
SET [from] = @InsertTo
WHERE [from] < @InsertFrom
AND [to] > @InsertTo
-- Trim lower end of row overlapping upper end of insert
UPDATE pricedata
SET [from] = @InsertTo
WHERE [from] >= @InsertFrom
AND [from] < @InsertTo
-- Trim upper end of row overlapping lower end of insert
UPDATE pricedata
SET [to] = @InsertFrom
WHERE [to] > @InsertFrom
AND [to] <= @InsertTo
-- Now that we have resolved any overlaps, we are clear to insert the new row
INSERT pricedata ([from], [to], price)
VALUES (@InsertFrom, @InsertTo, @InsertPrice)
请参阅此 db<>fiddle,它将上述逻辑封装在存储过程中,并演示了其在 OP 方案和其他几种情况下的操作。
评论
0赞
T N
10/31/2023
上述答案已与原始帖子进行了重大修改,以妥善处理需要拆分的重叠案例。
0赞
George Menoutis
10/31/2023
我很感激你的努力。我已经得到了一个答案,因为这样的算法并不存在。完成后,我会考虑发布我的代码。它比这复杂得多,因为已经存在的行和输入的组合应该涵盖任何多对多匹配的情况,
0赞
Charlieface
10/31/2023
允许多次插入的解决方案也很好。
0赞
T N
10/31/2023
@Charlieface - 它可能会变得复杂。我可以想象一种人为的情况,即现有行(范围)在两端被修剪,并根据传入的更新在中间分成三个方向。如果对现有行匹配(完全包含在)的传入行进行排序、编号并用于生成多个拆分行,则可能是可行的。这将是一个挑战。假设传入数据中没有重叠,其他重叠情况应该很简单。一种特殊情况是两个输入行一起通过从两侧攻击现有行来消除它。
上一个:计算 7 天内的活跃用户数
评论