【问题标题】:Select sum of hours grouped by a day first and then by a week选择按天分组的小时总和,然后按周分组
【发布时间】:2014-11-05 11:42:02
【问题描述】:

在 Oracle ApEx 中,我有一个这样的表:

CREATE TABLE  "ATTENDANCE_HOURS" 
   ("ID" NUMBER NOT NULL ENABLE, 
    "PERSON_ID" NUMBER, 
    "PROJECT_ID" NUMBER, 
    "FROM_X" DATE NOT NULL ENABLE, 
    "TO_X" DATE NOT NULL ENABLE, 
    "NOTE" VARCHAR2(300), 
    "APPROVED" NUMBER DEFAULT 0 NOT NULL ENABLE, 
    "APPROVAL_NOTE" VARCHAR2(300), 
    "DAY" DATE NOT NULL ENABLE, 
     CONSTRAINT "CHECK_TIMES" CHECK (TO_CHAR(TO_X, 'HH24MI') > TO_CHAR(FROM_X, 'HH24MI')) ENABLE, 
 CONSTRAINT "ATTENDANCE_HOURS_PK" PRIMARY KEY ("ID")
  USING INDEX  ENABLE
   )

注意:我无法更改表格。只是没有。 我需要为每个人选择他们每周工作多少小时。我已经选择了每天多少小时(感谢 StackOverflow),如下所示:

select 
    (MAX("TO_X") - MIN("FROM_X"))*24 - 
    (max(case when PROJECT_ID = 21 then to_x else to_date('01012000','DDMMYYYY') end) -
    max(case when PROJECT_ID = 21 then from_x else to_date('01012000','DDMMYYYY')       end))*24 AS TIME_SPENT
// project id = 21 is break
from #OWNER#.ATTENDANCE_HOURS
GROUP BY DAY

我想到的是,按周数对下一个条目进行分组并将整个内容放入 SUM(),但是,它不起作用,它说:不是单组分组函数。 或者我应该开始玩视图?

【问题讨论】:

  • 不清楚这些列的含义。什么定义了一个小时的工作?每个项目每人每天一排吗?为什么你的特殊套管项目 ID 21?
  • @Ben b/c 项目 21 是休息时间,不计入工作时间。

标签: sql oracle select oracle-apex


【解决方案1】:

每个人一周的总小时数如下所示:

select person_id, to_char(day, 'YYYY-WW') as week,
       sum(to_x - from_x) as hours_worked
from #OWNER#.ATTENDANCE_HOURS
group by person_id, to_char(day, 'YYYY-WW')
order by person_id, week;

我不知道项目 ID 上的额外逻辑是什么。你的问题没有解释它,所以我把它删除为计算小时总和是不必要的。如果它很重要,您可以重新添加它。

【讨论】:

  • 项目 ID 用于区分人们从事的项目,还有一个特殊项目 - 休息,不计入工作时间。
  • 对此答案+1。但请始终小心使用周数,尤其是在贝宁和年终时。例如,您希望 to_char(day, 'YYYY-WW') 表示 2015 年 1 月的第一天,如 2015-01,但结果可能是 2015-52,因为 1 月 1 日属于上一年的最后一周。有点有点混乱
【解决方案2】:

类似的东西(未经测试)?

select person_id
     , trunc(from_x,'iw')                                     first_day_of_iso_week
     , sum((to_x - from_x) * 24)                              all_hours
     , sum((case project_id when 21 then to_x - from_x) * 24) break_hours
  from attendance_hours
 group by person_id        -- for each person
     , trunc(from_x,'iw')  -- for each ISO-week

也许您需要一个额外的检查约束来说明 to_x 和 from_x 的日期部分应该相同,check(trunc(from_x) = trunc(to_x))?

编辑:我现在看到您的表中还有一个多余的 DAY 列。这不是一个好主意,因为您现在必须检查 (trunc(day) = trunc(to_x)) 和 trunc(day) = trunc(from_x)。如果可以,请去掉 day 列:它已经包含在您的 from_x 和 to_x 列中。

【讨论】:

    【解决方案3】:

    以下查询为您提供每个人的工作时间总和减去休息时间(假设项目 21 表示休息,所有其他表示工作):

    select person_id, 
      sum(case when project_id = 21 then -1 else 1 end * (to_x - from_x)) * 24
    from #OWNER#.ATTENDANCE_HOURS
    group by person_id;
    

    当工作可能超过午夜(甚至超过两天)时,每天获得这个可能会非常复杂。只要我们假设 from_x 和 to_x 是同一天离开,我们就会得到:

    select person_id, trunc(from_x),
      sum(case when project_id = 21 then -1 else 1 end * (to_x - from_x)) * 24
    from #OWNER#.ATTENDANCE_HOURS
    group by person_id, trunc(from_x);
    

    每周获得这个将是:

    select person_id, trunc(from_x, 'IW'),
      sum(case when project_id = 21 then -1 else 1 end * (to_x - from_x)) * 24
    from #OWNER#.ATTENDANCE_HOURS
    group by person_id, trunc(from_x, 'IW');
    

    编辑:哦,我只是注意到我对您的数据知之甚少。如果上午 10 点到上午 10:15 也有休息时间,项目出勤范围可以从上午 9 点到 11 点吗?然后我的查询工作。或者那会是两个项目出席,一个从上午 9 点到 10 点,另一个从上午 10:15 到上午 11 点?那么你需要sum(case when project_id = 21 then 0 else to_x - from_x end) * 24而不是。

    编辑:好的,正如您在评论中所说 project_id = 21 不能重叠,只需将其从您的查询中排除:

    select person_id, trunc(from_x, 'IW'), sum(to_x - from_x) * 24
    from #OWNER#.ATTENDANCE_HOURS
    where project_id <> 21 
    group by person_id, trunc(from_x, 'IW');
    

    【讨论】:

    • 对不起,我忘了提!每个项目花费的时间不能重叠,所以你描述的第二种方法是正确的。 :)
    • 好的,我已经相应地编辑了我的答案,以提供更简单的解决方案。
    猜你喜欢
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多