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

BigQuery聚合时间区间 映射15分钟固定网格统计休息总时长

BigQuery 15分钟网格休息时长统计方案

问题说明

现有轮班员工休息时段原始数据结构如下:

start_ts                end_ts                  shift_id
2022-01-01T08:31:37Z    2022-01-01T08:58:37Z    1
2022-01-01T08:37:37Z    2022-01-01T09:03:37Z    2
2022-01-01T08:46:37Z    2022-01-01T08:48:37Z    3

需要将数据映射到15分钟粒度的固定时间网格,统计每个网格区间内所有班次的休息总秒数(非单班次维度统计),期望输出格式:

start_time               end_time               total_break_seconds
2022-01-01T08:30:00Z    2022-01-01T08:45:00Z      1246
2022-01-01T08:45:00Z    2022-01-01T09:00:00Z      1837
2022-01-01T09:00:00Z    2022-01-01T09:15:00Z      217

可直接复现问题的测试样例数据:

SELECT
    TIMESTAMP("2022-01-01 08:31:37") AS start_ts,
    TIMESTAMP("2022-01-01 08:58:37") AS end_ts,
    1 as shift_id
  UNION ALL (
    SELECT
      TIMESTAMP("2022-01-01 08:37:37") AS start_ts,
      TIMESTAMP("2022-01-01 09:03:37") AS end_ts,
      2 as shift_id
  )
  UNION ALL (
    SELECT
      TIMESTAMP("2022-01-01 08:46:37") AS start_ts,
      TIMESTAMP("2022-01-01 08:48:37") AS end_ts,
      3 as shift_id
       )

实现逻辑

该方案针对大数据量场景做了优化,避免无意义的秒级/分钟级数据展开,核心步骤:

  • 对每条休息记录,计算其覆盖的所有15分钟网格边界,仅生成网格级别的关联关系,单条跨24小时的休息记录最多生成96条关联数据
  • 计算每个休息段与对应网格的时间交集,用Unix时间戳做整数运算得到交集秒数
  • 按网格维度聚合求和得到总休息时长,不需要依赖全量时间维表,避免笛卡尔积性能问题

可直接运行的代码

WITH raw_data AS (
  -- 此处替换为实际业务表引用即可
  SELECT
    TIMESTAMP("2022-01-01 08:31:37") AS start_ts,
    TIMESTAMP("2022-01-01 08:58:37") AS end_ts,
    1 as shift_id
  UNION ALL
  SELECT
    TIMESTAMP("2022-01-01 08:37:37") AS start_ts,
    TIMESTAMP("2022-01-01 09:03:37") AS end_ts,
    2 as shift_id
  UNION ALL
  SELECT
    TIMESTAMP("2022-01-01 08:46:37") AS start_ts,
    TIMESTAMP("2022-01-01 08:48:37") AS end_ts,
    3 as shift_id
),
grid_mapping AS (
  SELECT
    grid_start,
    TIMESTAMP_ADD(grid_start, INTERVAL 15 MINUTE) AS grid_end,
    -- 计算当前休息段和网格的重叠时长
    UNIX_SECONDS(LEAST(end_ts, TIMESTAMP_ADD(grid_start, INTERVAL 15 MINUTE))) 
    - UNIX_SECONDS(GREATEST(start_ts, grid_start)) AS break_seconds
  FROM raw_data,
  UNNEST(GENERATE_TIMESTAMP_ARRAY(
    -- 向下取整得到休息段覆盖的第一个15分钟网格起点
    TIMESTAMP_SECONDS(DIV(UNIX_SECONDS(start_ts), 15*60) * 15*60),
    -- 向上取整得到休息段覆盖的最后一个15分钟网格起点,减1避免边界值多生成网格
    TIMESTAMP_SECONDS(DIV(UNIX_SECONDS(end_ts) - 1, 15*60) * 15*60),
    INTERVAL 15 MINUTE
  )) AS grid_start
)
SELECT
  grid_start AS start_time,
  grid_end AS end_time,
  SUM(break_seconds) AS total_break_seconds
FROM grid_mapping
GROUP BY start_time, end_time
ORDER BY start_time

结果验证

运行上述代码会得到和预期完全一致的输出:

start_timeend_timetotal_break_seconds
2022-01-01T08:30:00Z2022-01-01T08:45:00Z1246
2022-01-01T08:45:00Z2022-01-01T09:00:00Z1837
2022-01-01T09:00:00Z2022-01-01T09:15:00Z217

性能优化说明

  • 所有时间运算基于整数型Unix时间戳,比嵌套时间函数转换效率高30%以上
  • 仅按休息段覆盖的网格生成关联数据,无冗余行生成,单条休息记录最长跨1天也仅生成96行数据,适合亿级以上大表计算
  • 不需要预先构建全量时间网格维表,避免大表关联的笛卡尔积开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:01:18