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

如何用Oracle SQL实现多用户基于10分钟间隔的工作时长统计

问题描述

我有一个Oracle数据库,用于存储用户每次操作的记录,希望统计每位用户的工作时长。统计规则如下:只要某个10分钟时段内存在用户操作,该时段即被计入"工作时间"。

例如,若用户在10:05和10:25各进行一次操作,则统计其工作时段为10:00-10:10和10:20-10:30,总计20分钟。

我需要编写一个SQL查询,按照上述逻辑分用户统计总工作时长。我曾实现了单用户场景下的预期结果,但当尝试适配多用户时,查询会无限运行。以下是适用于单用户的查询代码:

WITH database AS(
SELECT
    operation_date,
    user
FROM
    database
where 
    user = 'user1'
)
    ,start_date as (
  select 
  min (operation_date ) AS start_date,
         10 / 1440 AS time_interval
  from   database
)
, intervals as (
  select 
  
  start_date + ( ( level - 1 ) * time_interval ) start_date,
         start_date + ( ( level ) * time_interval ) end_date
  from   start_date
  connect by level <= 144
)

,timesum as(
  select
     user,
     to_char(start_date,'dd/mm/yyyy hh24:mi'),
     count ( operation_date ) as oper_num
  from   intervals
  left  join database
  on     start_date <= operation_date
  and    operation_date < end_date
  group  by user, start_date
  order  by start_date
  )
  
  select
  user,
  (count(oper_num)*10)/60 as hours
  from timesum
  where
  oper_num > 0
  group by user

请问如何修改以适配多用户场景?

解决方案

原查询在多用户场景下无限运行的核心原因是connect by未针对用户做隔离,导致生成时间区间时出现无限递归。以下是适配多用户的修改方案:

修改后的SQL

WITH user_time_ranges AS (
    -- 按用户分组,获取每个用户的最早操作时间和10分钟时间间隔
    SELECT 
        user_id,
        MIN(operation_date) AS user_min_date,
        10/1440 AS time_interval
    FROM 
        operation_records  -- 替换为你的实际表名,避免与关键字重名
    GROUP BY 
        user_id
),
user_intervals AS (
    -- 为每个用户独立生成其时间范围内的所有10分钟区间
    SELECT 
        utr.user_id,
        utr.user_min_date + ((level - 1) * utr.time_interval) AS interval_start,
        utr.user_min_date + (level * utr.time_interval) AS interval_end
    FROM 
        user_time_ranges utr
    CONNECT BY 
        level <= 144  -- 一天最多包含144个10分钟区间
        AND PRIOR utr.user_id = utr.user_id  -- 确保递归仅在同一用户维度内进行
        AND PRIOR sys_guid() IS NOT NULL  -- 防止Oracle优化导致的无限递归
),
user_interval_ops AS (
    -- 关联操作记录,统计每个用户的每个时间区间是否有操作
    SELECT 
        ui.user_id,
        COUNT(or_rec.operation_date) AS oper_num
    FROM 
        user_intervals ui
    LEFT JOIN 
        operation_records or_rec
        ON or_rec.user_id = ui.user_id
        AND or_rec.operation_date >= ui.interval_start
        AND or_rec.operation_date < ui.interval_end
    GROUP BY 
        ui.user_id, ui.interval_start
)
-- 最终统计每个用户的有效工作时长
SELECT 
    user_id,
    (COUNT(CASE WHEN oper_num > 0 THEN 1 END) * 10)/60 AS total_work_hours
FROM 
    user_interval_ops
GROUP BY 
    user_id;

关键修改点说明

  • 用户维度的区间生成:先按用户分组获取各自最早操作时间,再为每个用户独立生成时间区间,避免跨用户的无效区间。
  • CONNECT BY的隔离处理:添加PRIOR utr.user_id = utr.user_id确保递归仅在同一用户内执行,PRIOR sys_guid() IS NOT NULL规避Oracle优化引发的无限递归问题。
  • 表名与别名优化:避免使用database这类关键字作为表/别名,替换为更清晰的名称如operation_records,减少语法冲突。
  • 关联逻辑优化:关联操作记录时增加用户ID匹配,确保每个用户的操作仅与自身时间区间关联,避免笛卡尔积导致的性能损耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:53:25