计算员工在开始和结束日期之间应报告工作的天数

Posted

技术标签:

【中文标题】计算员工在开始和结束日期之间应报告工作的天数【英文标题】:Counting the number of days an employee is expected to report for work between their start and end dates 【发布时间】:2019-03-12 18:01:05 【问题描述】:

我正在使用 Oracle 12c。

我希望计算员工预计上班的天数,以最终报告每个部门每季度的缺勤率。我已经拼凑了一个虚拟表,其中包含每个部门的缺勤天数,我想加入该部门的预期天数(如果一个部门有 3 名员工,那么 5 天工作周有 3 x 5 = 15 人-天)。

我有一个CALENDAR 表,可以告诉我部门是否开放; IS_OPEN 字段中的“x”表示该部门是开放的,并且所有员工都应该报到上班,否则表示该部门已关闭。

CALENDAR(
    DEPT_ID VARCHAR2(8) NOT NULL,
    QUARTER VARCHAR2(8) NOT NULL,
    CALENDAR_DATE DATE NOT NULL,
    IS_OPEN VARCHAR2(1) NOT NULL
)
DEPT_ID | QUARTER | CALDR_DATE | IS_OPEN
--------|---------|------------|---------
ACCTING | 2019Q1  | 2019-03-02 | ' '
MFGING  | 2019Q1  | 2019-03-02 | x
MRKTING | 2019Q1  | 2019-03-02 | ' '
ACCTING | 2019Q1  | 2019-03-03 | x
MFGING  | 2019Q1  | 2019-03-03 | x
MRKTING | 2019Q1  | 2019-03-03 | x
ACCTING | 2019Q1  | 2019-03-04 | x
MFGING  | 2019Q1  | 2019-03-04 | x
MRKTING | 2019Q1  | 2019-03-04 | x
...

我还有一个TRANSACTIONS 表,它告诉我员工的开始日期和结束日期(TRANS_TYPE 4 是开始日期,TRANS_TYPE 5 是结束日期)。

TRANSACTIONS(
    DEPT_ID VARCHAR2(8) NOT NULL,
    QUARTER VARCHAR2(8) NOT NULL,
    TRANSACTION_DATE DATE NOT NULL,
    TRANSACTION_TYPE NUMBER(1,0) NOT NULL,
    EMPLOYEE_ID VARCHAR2(13) NOT NULL
)
DEPT_ID | QUARTER | TRANS_DATE | TRANS_TYPE | EMPLOYEE_ID
--------|---------|------------|------------|------------
...
MFGING  | 2019Q1  | 2019-01-07 |          4 | 123
MRKTING | 2019Q1  | 2019-01-28 |          4 | 456
MFGING  | 2019Q1  | 2019-02-01 |          5 | 123
...

在上表中,员工 123 于 1 月 7 日开始工作,并于 2 月 1 日离开部门。员工 456 于 1 月 28 日开始工作,至今仍在该部门工作。

从上面的例子中不明显:任何在上一季度担任部门成员的员工在第一天上班时将自动获得TRANS_TYPE4季度(他们在上一季度的最后一天没有得到TRANS_TYPE 5)。

我想连接这两个表,以便生成的虚拟表具有以下字段:DEPT_IDQUARTERCALDR_DATEEMPLOYEE_IDATTENDANCE_EXPECTEDDEPT_IS_OPEN(可选),其中ATTENDANCE_EXPECTED 字段包含“1”,如果员工预计当天上班(即,部门是开放的,CALDR_DATE 在员工的开始日期和结束日期之间或SYSDATE 如果没有结束日期存在)。

然后我可以从结果表中SUM(ATTENDANCE_EXPECTED)(或者可能在过滤DEPT_IS_OPEN之后COUNT(*)),并按DEPT_IDQUARTER分组以获得每个部门和季度的人日数.

我不知道如何扩展行,以便从开始日期到结束日期(如果没有结束日期,则为当前日期)的每一天,每个员工每天都有一行。

我该怎么做,或者有没有更好的方法来计算每个部门每季度的人日?

谢谢。

【问题讨论】:

您如何处理假期、病假、假期、陪审团职责以及员工不上班但不会“缺勤”的其他原因? 我的“count_absences”查询运行良好;对于不同类型的缺勤,我们有不同的代码,计算中只包含某些代码。这会影响ATTENDANCE_EXPECTED天数,但误差应该小到可以忽略不计。 【参考方案1】:

这可能有效

解释: - 查找部门的所有开放日,不感兴趣的关闭日 - 如果加入该部门的所有员工/交易 --- 日历日期 >= 类型 4 的跨日期 --- 和 calender_date - 一个公寓的雇员是一个事务表中类型为 4 的事务

select c.DEPT_ID, c.QUARTER, c.CALENDAR_DATE, e.EMPLOYEE_ID, 1 ATTENDANCE_EXPECTED, c.IS_OPEN
from calendar c, 
     transactions e
where c.dept_id = e.dept_id
  and c.quarter = e.quarter
  and c.IS_OPEN = 'x'
  and e.transaction_type = 4
  and c.calendar_date < NVL((select transaction_date from transactions where dept_id = e.dept_id and Employee_Id = e.employee_id and quarter = e.quarter and transaction_type = 5),sysdate)
  and c.calendar_date >= (select transaction_date from transactions where dept_id = e.dept_id and Employee_Id = e.employee_id and quarter = e.quarter and transaction_type = 4);

【讨论】:

这个解决方案大部分都有效。当我针对我的实际数据运行它时,它给了我一个“ORA-01427: single-row subquery returns more than one row”错误,但是在将hashbrown's solution 应用于两个子查询之后,它运行良好。谢谢。【参考方案2】:
    select c.DEPT_ID, c.QUARTER, 
       c.CALENDAR_DATE, 
       e.EMPLOYEE_ID, 
       case when c.CALENDAR_DATE between 
                    e.TRANSACTION_DATE and NVL(t.TRANSACTION_DATE, c.CALENDAR_DATE)  
        then 1 else 0 end ATTENDANCE_EXPECTED, 
       CASE when c.IS_OPEN = 'x' then 1 else 0 end is_open
from calendar c 
LEFT JOIN transactions e 
       ON c.dept_id = e.dept_id
      and c.quarter = e.quarter
      and e.transaction_type = 4
left JOIN transactions t 
       ON t.transaction_type = 5
      and t.EMPLOYEE_ID = e.EMPLOYEE_ID;

更多行供查看,在这里您可以过滤和统计非营业日demo

【讨论】:

以上是关于计算员工在开始和结束日期之间应报告工作的天数的主要内容,如果未能解决你的问题,请参考以下文章

SQL是计算两个日期相差多少天数的函数?

计算日期之间的天数,不计算周六和周日[重复]

SQL 计算两个日期相差多少天数的函数

js 怎么计算 开始日期(2011-02-22)+天数(3)=结束日期(2011-02-24)

如何用excel计算两个日期之间相差的年数和月数

(013)每日SQL学习:确定两个日期之间的工作日天数和计算一年周内各日期次数