我正在使用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_TYPE
4(他们没有得到TRANS_TYPE
5上一季度的最后一天)。
我想加入这两个表,以便生成的虚拟表具有以下字段:DEPT_ID
,QUARTER
,CALDR_DATE
,EMPLOYEE_ID
,ATTENDANCE_EXPECTED
,DEPT_IS_OPEN
(可选),如果要求员工报告,ATTENDANCE_EXPECTED
字段包含'1'那天的工作(即,部门是开放的,CALDR_DATE
在员工的开始日期和结束日期之间,如果没有结束日期,则为SYSDATE
)。
然后我可以从结果表中SUM(ATTENDANCE_EXPECTED)
(或者在过滤COUNT(*)
后可能是DEPT_IS_OPEN
),然后由DEPT_ID
,QUARTER
分组以获得每个部门和季度的人日数。
我无法弄清楚如何扩展行,以便从开始日期到结束日期每天每位员工每行一行(如果没有结束日期,则为当前日期)。
我该怎么做,或者有更好的方法来计算每个部门每个季度的人日数?
谢谢。
这可能会奏效
解释: - 查找部门的所有开放日期,关闭日期不感兴趣 - 加入该部门的所有员工/交易,如果 ---日历日期> =类型为4的转换日期 ---和calender_date <与类型5的转换日期 - 公寓中的员工是交易表中类型为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);
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;
更多行供查看,在这里您可以过滤和计算non_open天demo