Oracle SQL - 需要帮助将一个日期值 EFF_DT 转换为具有唯一标准的日期范围 START_EFF_DT 和 END_EFF_DT
Oracle SQL - need help converting from one date value EFF_DT to a date range of START_EFF_DT and END_EFF_DT with unique criteria
我遇到了这个问题,我正在寻求有关此问题的任何帮助
背景:
我需要创建一个查询,根据我们 Oracle 数据库中可用的数据识别所有“无薪”工作日
我们的时间和劳动力跟踪数据仅包含 1 个代表“工作日期”的日期列 (EFF_DT)
原始 table 的简化版本如下所示:
EEID
WORK_DT
PAYCODE
1111
2022/03/01
UNPAID
1111
2022/03/02
REG_WORK
1111
2022/03/03
REG_WORK
1111
2022/03/04
UNPAID
1111
2022/03/05
UNPAID
1111
2022/03/06
SICK
1111
2022/03/07
SICK
1111
2022/03/08
UNPAID
1111
2022/03/09
UNPAID
1111
2022/03/10
UNPAID
我需要做的是仅过滤“UNPAID”行,然后我需要确定 start/end 无薪休假工作日期的“范围”
因此预期结果需要如下所示:
EEID
START_EFF_DT
END_EFF_DT
1111
2022/03/01
2022/03/01
1111
2022/03/04
2022/03/05
1111
2022/03/08
2022/03/10
我应该如何为需要创建的 crystal 报告设计此 SQL?
非常感谢任何帮助!
在 Oracle 12.1 及更高版本中,您可以使用 match_recognize
解决各种 pattern-matching 问题。
测试数据:
create table time_labor (eeid number, work_dt date, paycode varchar2(10));
alter session set nls_date_format = 'yyyy/mm/dd';
insert into time_labor (eeid, work_dt, paycode)
select 1111, to_date('2022/03/01'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/02'), 'REG_WORK' from dual union all
select 1111, to_date('2022/03/03'), 'REG_WORK' from dual union all
select 1111, to_date('2022/03/04'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/05'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/06'), 'SICK' from dual union all
select 1111, to_date('2022/03/07'), 'SICK' from dual union all
select 1111, to_date('2022/03/08'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/09'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/10'), 'UNPAID' from dual
;
commit;
查询和输出:
select eeid, start_eff_dt, end_eff_dt
from time_labor
match_recognize(
partition by eeid
order by work_dt
measures first(work_dt) as start_eff_dt,
last (work_dt) as end_eff_dt
pattern ( unpaid+ )
define unpaid as paycode = 'UNPAID'
);
EEID START_EFF_DT END_EFF_DT
---- ------------ ------------
1111 2022/03/01 2022/03/01
1111 2022/03/04 2022/03/05
1111 2022/03/08 2022/03/10
match_recognize
机器对输入行进行分区,并根据 partition by
和 order by
子句在每个分区内对它们进行排序。它查找模式 unpaid+
的匹配项,这意味着一个或多个连续的行被分类为 unpaid
,其中该分类在 define
子句中定义。 (这里 unpaid
只是我为这个分类器选择的名称;这似乎是一个合理的选择,但它可以称为任何其他有效标识符,例如 x
或 abc_2902
) . match_recognize
returns 默认情况下每个匹配一行,使用 measures
子句中的额外计算表达式。
对于无法使用 match_recognize
子句的旧版本 Oracle 数据库(版本 12.1 之前)的用户,这里有一个仅使用分析函数的解决方案和一个非常好的识别间隙和孤岛的方法,已知作为“固定差异”或“tabibito-san”方法。诀窍是在辅助子查询中创建附加分组表达式,标记为 grp
(为了便于阅读,我在 with
子句中开始)。
with
prep as (
select eeid, work_dt, paycode,
row_number() over (partition by eeid order by work_dt)
- row_number() over (partition by eeid, paycode order by work_dt)
as grp
from time_labor
)
select eeid, min(work_dt) as start_eff_dt, max(work_dt) as end_eff_dt
from prep
group by eeid, paycode, grp
having paycode = 'UNPAID'
order by eeid, start_eff_dt
;
示例数据(用于测试)和此查询的输出可以在另一个答案中找到,该答案使用 match_recognize
(仅限 Oracle 版本 >= 12.1)
我遇到了这个问题,我正在寻求有关此问题的任何帮助
背景: 我需要创建一个查询,根据我们 Oracle 数据库中可用的数据识别所有“无薪”工作日
我们的时间和劳动力跟踪数据仅包含 1 个代表“工作日期”的日期列 (EFF_DT)
原始 table 的简化版本如下所示:
EEID | WORK_DT | PAYCODE |
---|---|---|
1111 | 2022/03/01 | UNPAID |
1111 | 2022/03/02 | REG_WORK |
1111 | 2022/03/03 | REG_WORK |
1111 | 2022/03/04 | UNPAID |
1111 | 2022/03/05 | UNPAID |
1111 | 2022/03/06 | SICK |
1111 | 2022/03/07 | SICK |
1111 | 2022/03/08 | UNPAID |
1111 | 2022/03/09 | UNPAID |
1111 | 2022/03/10 | UNPAID |
我需要做的是仅过滤“UNPAID”行,然后我需要确定 start/end 无薪休假工作日期的“范围”
因此预期结果需要如下所示:
EEID | START_EFF_DT | END_EFF_DT |
---|---|---|
1111 | 2022/03/01 | 2022/03/01 |
1111 | 2022/03/04 | 2022/03/05 |
1111 | 2022/03/08 | 2022/03/10 |
我应该如何为需要创建的 crystal 报告设计此 SQL?
非常感谢任何帮助!
在 Oracle 12.1 及更高版本中,您可以使用 match_recognize
解决各种 pattern-matching 问题。
测试数据:
create table time_labor (eeid number, work_dt date, paycode varchar2(10));
alter session set nls_date_format = 'yyyy/mm/dd';
insert into time_labor (eeid, work_dt, paycode)
select 1111, to_date('2022/03/01'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/02'), 'REG_WORK' from dual union all
select 1111, to_date('2022/03/03'), 'REG_WORK' from dual union all
select 1111, to_date('2022/03/04'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/05'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/06'), 'SICK' from dual union all
select 1111, to_date('2022/03/07'), 'SICK' from dual union all
select 1111, to_date('2022/03/08'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/09'), 'UNPAID' from dual union all
select 1111, to_date('2022/03/10'), 'UNPAID' from dual
;
commit;
查询和输出:
select eeid, start_eff_dt, end_eff_dt
from time_labor
match_recognize(
partition by eeid
order by work_dt
measures first(work_dt) as start_eff_dt,
last (work_dt) as end_eff_dt
pattern ( unpaid+ )
define unpaid as paycode = 'UNPAID'
);
EEID START_EFF_DT END_EFF_DT
---- ------------ ------------
1111 2022/03/01 2022/03/01
1111 2022/03/04 2022/03/05
1111 2022/03/08 2022/03/10
match_recognize
机器对输入行进行分区,并根据 partition by
和 order by
子句在每个分区内对它们进行排序。它查找模式 unpaid+
的匹配项,这意味着一个或多个连续的行被分类为 unpaid
,其中该分类在 define
子句中定义。 (这里 unpaid
只是我为这个分类器选择的名称;这似乎是一个合理的选择,但它可以称为任何其他有效标识符,例如 x
或 abc_2902
) . match_recognize
returns 默认情况下每个匹配一行,使用 measures
子句中的额外计算表达式。
对于无法使用 match_recognize
子句的旧版本 Oracle 数据库(版本 12.1 之前)的用户,这里有一个仅使用分析函数的解决方案和一个非常好的识别间隙和孤岛的方法,已知作为“固定差异”或“tabibito-san”方法。诀窍是在辅助子查询中创建附加分组表达式,标记为 grp
(为了便于阅读,我在 with
子句中开始)。
with
prep as (
select eeid, work_dt, paycode,
row_number() over (partition by eeid order by work_dt)
- row_number() over (partition by eeid, paycode order by work_dt)
as grp
from time_labor
)
select eeid, min(work_dt) as start_eff_dt, max(work_dt) as end_eff_dt
from prep
group by eeid, paycode, grp
having paycode = 'UNPAID'
order by eeid, start_eff_dt
;
示例数据(用于测试)和此查询的输出可以在另一个答案中找到,该答案使用 match_recognize
(仅限 Oracle 版本 >= 12.1)