合并两个时间序列数据表的技术实现咨询
合并两个时间序列数据表的技术实现咨询
看起来你需要的是基于时间区间优先级的合并——表2的level值要覆盖表1对应区间的内容,同时还要把原来的规则/不规则区间拆分成所有重叠后的最小粒度区间。这个需求的核心是先把所有时间节点拆解重组,再关联两张表取优先级值,我来给你详细说下实现思路和具体SQL写法:
原始表结构与数据
表1(规则30分钟间隔)
| periodFrom | periodTo | timeFrom | timeTo | levelFrom | levelTo |
|---|---|---|---|---|---|
| 1 | 1 | 00:00 | 00:30 | 50 | 50 |
| 2 | 2 | 00:30 | 01:00 | 50 | 50 |
| 3 | 3 | 01:00 | 01:30 | 50 | 50 |
| 4 | 4 | 01:30 | 02:00 | 50 | 50 |
表2(不规则间隔,level优先级更高)
| periodFrom | periodTo | timeFrom | timeTo | levelFrom | levelTo |
|---|---|---|---|---|---|
| 1 | 3 | 00:15 | 01:15 | 0 | 0 |
| 4 | 4 | 01:30 | 01:32 | 50 | 60 |
| 4 | 4 | 01:32 | 01:43 | 60 | 60 |
目标表3(合并后结果)
| periodFrom | periodTo | timeFrom | timeTo | levelFrom | levelTo |
|---|---|---|---|---|---|
| 1 | 1 | 00:00 | 00:15 | 50 | 50 |
| 1 | 1 | 00:15 | 00:30 | 0 | 0 |
| 2 | 2 | 00:30 | 01:00 | 0 | 0 |
| 3 | 3 | 01:00 | 01:15 | 0 | 0 |
| 3 | 3 | 01:15 | 01:30 | 50 | 50 |
| 4 | 4 | 01:30 | 01:32 | 50 | 60 |
| 4 | 4 | 01:32 | 01:43 | 60 | 60 |
| 4 | 4 | 01:43 | 02:00 | 50 | 50 |
实现思路
- 收集所有时间节点:把表1和表2中所有的
timeFrom和timeTo提取出来,去重后排序,得到所有需要拆分的时间点。这些点会把原来的大区间拆分成最小粒度的不重叠区间。 - 生成基础时间区间:用排序后的时间点生成连续的
(timeFrom, timeTo)区间,每个区间是相邻两个时间点。 - 关联原始表取优先级值:把生成的基础区间分别和表1、表2关联,找到每个区间对应的
period和level值,其中表2的level优先级高于表1(用COALESCE优先取表2的值,表2没有则用表1的)。 - 过滤无效区间:确保最终的区间都是有效的(
timeFrom < timeTo),并且对应到正确的period。
具体SQL实现(以PostgreSQL为例,可适配其他数据库)
-- 第一步:收集所有时间节点 WITH all_time_points AS ( SELECT timeFrom AS point FROM table1 UNION SELECT timeTo AS point FROM table1 UNION SELECT timeFrom AS point FROM table2 UNION SELECT timeTo AS point FROM table2 ), -- 第二步:生成连续的时间区间 time_intervals AS ( SELECT a.point AS timeFrom, LEAD(a.point) OVER (ORDER BY a.point) AS timeTo FROM all_time_points a ) -- 第三步:关联两张表,取优先级值 SELECT COALESCE(t2.periodFrom, t1.periodFrom) AS periodFrom, COALESCE(t2.periodTo, t1.periodTo) AS periodTo, ti.timeFrom, ti.timeTo, COALESCE(t2.levelFrom, t1.levelFrom) AS levelFrom, COALESCE(t2.levelTo, t1.levelTo) AS levelTo FROM time_intervals ti -- 关联表1:找到当前时间区间属于表1的哪个period LEFT JOIN table1 t1 ON ti.timeFrom >= t1.timeFrom AND ti.timeTo <= t1.timeTo -- 关联表2:找到当前时间区间属于表2的哪个period(优先级更高) LEFT JOIN table2 t2 ON ti.timeFrom >= t2.timeFrom AND ti.timeTo <= t2.timeTo -- 过滤掉无效的区间(最后一个点的LEAD会是NULL) WHERE ti.timeTo IS NOT NULL ORDER BY ti.timeFrom;
关键细节说明
- 时间节点收集:用
UNION自动去重,确保每个时间点只出现一次,排序后生成的区间不会重复。 - LEAD窗口函数:用来获取下一个时间点,生成连续的区间。如果是MySQL等不支持窗口函数的数据库,可以用自连接来实现类似逻辑。
- COALESCE函数:专门用来处理优先级取值——如果表2有对应区间的level值,就用表2的;没有的话 fallback 到表1的值,完美匹配你的需求。
- 区间关联条件:
ti.timeFrom >= tX.timeFrom AND ti.timeTo <= tX.timeTo确保每个小区间完全落在原始表的某个大区间内,避免跨区间的错误关联。
这个方案可以灵活处理表1和表2的任意时间间隔,不管是规则还是不规则的,都能正确拆分并合并优先级数据。
备注:内容来源于stack exchange,提问作者Anthony W
相关产品推荐
相关产品推荐

