【问题标题】:Grouping data by week按周分组数据
【发布时间】:2020-07-21 20:14:35
【问题描述】:

我正在寻找一种方法将下面的 emp_attendance 行分组为周一至周日的几周。

我在互联网上看到了一些关于“IW”格式的内容,但我认为这不会让我进行分组,也许我做错了什么。此外,诸如 12312020 Thursday 和 01012021 Friday 这样的日期应该组合在一起,因为它们介于星期一和星期日之间,但它们是不同的年份。

我当前的代码正在汇总所有数据并产生以下输出

  select   e.employee_id, 
               e.first_name,    
               e.last_name,

        trunc(sum(a.end_date - a.start_date) * 24) hours,

       trunc(mod(sum(a.end_date - a.start_date) * 24 * 60,60)) minutes,

        round(mod(sum(a.end_date - a.start_date) * 24 * 60 * 60,60)) seconds

 from    employees e,       emp_attendance a

   where a.employee_id = e.employee_id 

  group by e.employee_id, 
           e.first_name, e.last_name

 order by e.employee_id, 
                  e.first_name,   
                e.last_name;


EMPLOYEE_ID    FIRST_NAME    
LAST_NAME    HOURS    
MINUTES    SECONDS
  1    John    Doe    128    51    19

我正在寻找产生这个输出。请注意,对于组中的每一行,我需要相同的 group_id 和 start_date 组的 MONDAY 和 end_date 组的星期日,以便我可以在需要时回溯数据的来源。

如果没有员工的 emp_attendance 记录,请不要添加空行。在我的示例中,虽然员工 2 和 3 存在,但他们应该没有输出。

感谢所有回答的人

GROUP_ID  
EMPLOYEE_ID    FIRST_NAME    
LAST_NAME    HOURS    MINUTES    SECONDS.    
START_DATE END_DATE 
 1 1    John    Doe    46    0    58 07202020 07262020
2 1    John    Doe    73    37    14 07272020 08022020 
3 1    John    Doe  9    13    7 08032020 08082020



ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';

  Create table employees(
  employee_id Number(6),
  first_name VARCHAR2(20),
  last_name VARCHAR2(20),
  hourly_rate NUMBER
 );

  INSERT INTO employees(
   employee_id,
   first_name,
   last_name,
   hourly_rate)
  VALUES 
  (1, 'John', 'Doe', 55.05);


  INSERT INTO employees(
   employee_id,
   first_name,
   last_name,
   hourly_rate)
  VALUES 
  (2, 'Jane', 'Smith', 45.50);


  INSERT INTO employees(
   employee_id,
   first_name,
   last_name,
   hourly_rate)
  VALUES 
  (3, 'Mike', 'Jones', 25.00);


  create table emp_attendance(
    employee_id NUMBER(6),
    start_date DATE,
   end_date DATE
   );

INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('08032020 12:12:12', 'MMDDYYYY HH24:MI:SS'),

 TO_DATE('08032020 21:25:19', 'MMDDYYYY HH24:MI:SS'));



  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('08022020 12:12:12', 'MMDDYYYY HH24:MI:SS'),

 TO_DATE('08032020 19:25:19', 'MMDDYYYY HH24:MI:SS'));


  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07212020 07:22:22', 'MMDDYYYY HH24:MI:SS'),

 TO_DATE('07212020 14:49:13', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07222020 08:08:43', 'MMDDYYYY HH24:MI:SS'),

 TO_DATE('07222020 16:15:55', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07232020 08:18:17', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07232020 15:58:16', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07242020 10:50:15', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07242020 18:21:41', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
 employee_id,
 start_date,
 end_date)
VALUES 
   (1,
 TO_DATE('07252020 18:06:11', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07262020 01:34:37', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07262020 10:57:07', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07262020 18:44:11', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07272020 09:35:44', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07272020 16:14:13', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07282020 07:08:31', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07282020 17:17:12', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07292020 05:38:27', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07292020 13:06:49', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07302020 08:11:51', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('07302020 18:29:40', 'MMDDYYYY HH24:MI:SS'));

  INSERT INTO emp_attendance(
  employee_id,
  start_date,
  end_date)
  VALUES 
  (1,
  TO_DATE('07312020 18:01:51', 'MMDDYYYY HH24:MI:SS'),

  TO_DATE('08012020 01:52:37', 'MMDDYYYY HH24:MI:SS'));

【问题讨论】:

  • 包含数据的预期结果会很有帮助),最好是原始数据的表格表示,以及插入语句)。你想要每周一个总数吗?还是每个员工每周一个? (如果员工在给定的一周没有时间 - 显示为零怎么办?)如果开始日期是星期天,结束日期是星期一,那属于哪一周?或者您想将该行分成两个星期,每个星期都有适当的时间?
  • @Alex 我知道已经有一段时间了,但我终于回到了这个项目。在您的解决方案中,每周数字将围绕每年循环,以防止每年同一周的总和我可以在 YYYY 与开始日期的 week_number 连接上求和。因此,如果运行多年,给我一个静态 SUM 和不同的行?
  • trunc(...., 'IW') 保留年份,因此您无需执行任何其他操作。 Week 12 appears twice here,不同年份,不同的实际日期。如果您要显示周数,那么您可以从聚合后的截断值中获得该周数和年份。
  • @Alex 已经小心了。感谢回复

标签: sql oracle week-number


【解决方案1】:

在上面的数据库结构中,您可以在表中使用列 start_date emp_attendance 计算当前周数,然后根据它进行分组。

您可以使用带有圆形功能的附加参数 轮(列名,轮数) 对第二个参数使用负值

-1 表示舍入到 10s

-2 表示舍入到 100s

-3 表示舍入到 1000s

等等……

查询应该类似于以下内容:

select to_char(a.start_date, 'WW') weekNumber, e.employee_id, e.first_name,  e.last_name, 
 trunc(sum(a.end_date - a.start_date) * 24) hours, 
trunc(mod(sum(a.end_date - a.start_date) * 24 * 60,60)) minutes,          
round(mod(sum(a.end_date - a.start_date) * 24 * 60,60), -1) rounded_minutes,   
round(mod(sum(a.end_date - a.start_date) * 24 * 60 * 60,60)) seconds 
from employees e, emp_attendance a 
where a.employee_id = e.employee_id
group by e.employee_id, e.first_name, e.last_name ,to_char(a.start_date, 'WW')
-- order by first column = weekNumber then by other columns
order by 1, e.employee_id, e.first_name,  e.last_name;

【讨论】:

    【解决方案2】:

    有很多类似主题的帖子,所以我会随时链接它们->

    1. 这篇文章可以帮助你按周分组数据并进行分组计算Oracle SQL - Sum and group data by week
    2. 然后您可以使用 mySQL ROUND() 函数并将参数设置为四舍五入到最接近的 10 位。在此处找到的文档 https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions135.htm

    【讨论】:

    • 谢谢,但这些命令是特定于 sql server 的,我正在运行 Oracle
    【解决方案3】:

    您可以使用the trunc() function 和 ISO 周'IW' element 获得一周的星期一;然后按该字段以及您的其他字段进行分组:

    select e.employee_id,
      e.first_name,
      e.last_name,
      trunc(a.start_date, 'IW') as week,
      trunc(sum(a.end_date - a.start_date) * 24) hours,
      trunc(mod(sum(a.end_date - a.start_date) * 24 * 60,60)) minutes,
      round(mod(sum(a.end_date - a.start_date) * 24 * 60 * 60,60)) seconds
    from employees e
    join emp_attendance a on a.employee_id = e.employee_id
    group by e.employee_id, e.first_name, e.last_name, trunc(a.start_date, 'IW')
    order by e.employee_id, e.first_name, e.last_name, trunc(a.start_date, 'IW');
    
    EMPLOYEE_ID | FIRST_NAME | LAST_NAME | WEEK              | HOURS | MINUTES | SECONDS
    ----------: | :--------- | :-------- | :---------------- | ----: | ------: | ------:
              1 | John       | Doe       | 07202020 00:00:00 |    46 |       0 |      58
              1 | John       | Doe       | 07272020 00:00:00 |    73 |      37 |      14
              1 | John       | Doe       | 08032020 00:00:00 |     9 |      13 |       7
    

    要获得您想要的输出,您可以处理截断的日期,并为组 ID 添加 row_number()

    select row_number() over (order by trunc(a.start_date, 'IW')) as group_id,
      e.employee_id,
      e.first_name,
      e.last_name,
      trunc(sum(a.end_date - a.start_date) * 24) hours,
      trunc(mod(sum(a.end_date - a.start_date) * 24 * 60,60)) minutes,
      round(mod(sum(a.end_date - a.start_date) * 24 * 60 * 60,60)) seconds,
      to_char(trunc(a.start_date, 'IW'), 'MMDDYYYY') as start_date,
      to_char(trunc(a.start_date, 'IW') + 6, 'MMDDYYYY') as end_date
    from employees e
    join emp_attendance a on a.employee_id = e.employee_id
    group by e.employee_id, e.first_name, e.last_name, trunc(a.start_date, 'IW')
    order by e.employee_id, e.first_name, e.last_name;
    
    GROUP_ID | EMPLOYEE_ID | FIRST_NAME | LAST_NAME | HOURS | MINUTES | SECONDS | START_DATE | END_DATE
    -------: | ----------: | :--------- | :-------- | ----: | ------: | ------: | :--------- | :-------
           1 |           1 | John       | Doe       |    46 |       0 |      58 | 07202020   | 07262020
           3 |           1 | John       | Doe       |     9 |      13 |       7 | 08032020   | 08092020
           2 |           1 | John       | Doe       |    73 |      37 |      14 | 07272020   | 08022020
    

    db<>fiddle为当前数据;和for the original data

    【讨论】:

    • 完美。感谢您的专业知识和详细解释
    猜你喜欢
    • 2019-08-08
    • 2021-06-01
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 2020-09-21
    • 1970-01-01
    相关资源
    最近更新 更多