You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL实现:从含汇总时段数据的源表t_times生成拆分后的时段表t_slots

嘿,这个需求完全不用麻烦游标!咱们用集合式SQL就能轻松搞定,效率还高得多。核心思路是先生成对应数量的数字序列,再基于原表的时间和间隔计算每个子时段的起止时间。下面分几种主流数据库给你具体的实现方案:

PostgreSQL 实现

PostgreSQL自带的generate_series函数简直是为这种场景量身定做的,代码简洁又高效:

INSERT INTO t_slots (start_time, end_time, duration)
SELECT
    -- 计算子时段开始时间:原起始时间加上(n-1)个间隔时长
    t.start_time + (s.n - 1) * INTERVAL '1 minute' * t.slot_duration AS start_time,
    -- 子时段结束时间就是开始时间加一个间隔
    t.start_time + s.n * INTERVAL '1 minute' * t.slot_duration AS end_time,
    t.slot_duration AS duration
FROM t_times t
-- 为每条原记录生成1到number_of_slots的数字序列,对应要生成的行数
CROSS JOIN generate_series(1, t.number_of_slots) s(n);

generate_series(1, t.number_of_slots)会自动为t_times里的每条记录生成对应数量的数字行,再通过时间运算直接算出每个子时段的起止。

MySQL 8.0+ 实现

MySQL 8.0及以上支持递归CTE,我们可以用它生成足够多的数字序列,再和原表关联:

WITH RECURSIVE nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < (SELECT MAX(number_of_slots) FROM t_times)
)
INSERT INTO t_slots (start_time, end_time, duration)
SELECT
    ADDTIME(t.start_time, SEC_TO_TIME((n - 1) * t.slot_duration * 60)) AS start_time,
    ADDTIME(t.start_time, SEC_TO_TIME(n * t.slot_duration * 60)) AS end_time,
    t.slot_duration AS duration
FROM t_times t
JOIN nums ON nums.n <= t.number_of_slots;

先递归生成从1到t_times中最大number_of_slots的数字序列,再通过JOIN只保留每条原记录需要的行数,最后用ADDTIME和SEC_TO_TIME计算时间。

SQL Server 实现

SQL Server同样可以用递归CTE生成数字序列,配合DATEADD函数计算时间:

WITH nums AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM nums WHERE n < (SELECT MAX(number_of_slots) FROM t_times)
)
INSERT INTO t_slots (start_time, end_time, duration)
SELECT
    DATEADD(MINUTE, (n - 1) * t.slot_duration, t.start_time) AS start_time,
    DATEADD(MINUTE, n * t.slot_duration, t.start_time) AS end_time,
    t.slot_duration AS duration
FROM t_times t
JOIN nums ON nums.n <= t.number_of_slots
OPTION (MAXRECURSION 0); -- 如果number_of_slots超过100,必须加上这个选项

递归生成数字序列后,用DATEADD直接给原起始时间加上对应分钟数得到子时段。OPTION (MAXRECURSION 0)是为了避免默认递归次数(100次)不够的问题。

通用思路总结

不管用哪种数据库,核心逻辑都是这三步:

  • 生成一个数字序列,覆盖从1到每条记录number_of_slots的范围
  • 将原表和数字序列关联,得到对应数量的行
  • 计算每个子时段的时间:
    • 子时段开始时间 = 原start_time + (n-1)*slot_duration分钟
    • 子时段结束时间 = 原start_time + n*slot_duration分钟
    • duration直接复用原表的slot_duration

这种集合式操作比游标高效太多,数据库优化器能更好地处理批量数据,代码也更简洁易维护。

内容的提问来源于stack exchange,提问作者James F

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 22:57:31