我有一份工作清单,表明在任何特定工作上执行的工作。当白天完成工作时,只添加一条记录并包含work_type。 周末不进行工作。乔布斯可以在很长一段时间内完成工作,在这里和那里度过了奇怪的一天,但在其生命周期的某个阶段,它应该有一段时间的工作,以便始终如一地进行工作。 我们的管理层希望能够在报告中突出显示没有发生这种较长时间工作的任何工作。 围绕工作类型和团队名称还有其他一些条件,但主要的问题是时间问题。
那么......我怎样才能找到工作时间连续不超过两周(10个工作日)的工作?
在下文中,作业164353将不包括在内,因为它必须连续10天(忽略周末),而作业214325将被标记为9日有间隔打破连续几天的序列。
JOB_ID W ACTION_DATE
---------- - -----------
164354 H 10-FEB-17
164354 H 13-FEB-17
164354 H 14-FEB-17
164354 H 15-FEB-17
164354 H 16-FEB-17
164354 H 17-FEB-17
164354 H 20-FEB-17
164354 H 21-FEB-17
164354 H 22-FEB-17
164354 H 23-FEB-17
164354 H 24-FEB-17
214325 H 01-MAR-17
214325 H 02-MAR-17
214325 H 03-MAR-17
214325 H 06-MAR-17
214325 H 07-MAR-17
214325 H 08-MAR-17
214325 H 10-MAR-17
214325 H 13-MAR-17
214325 H 14-MAR-17
214325 H 15-MAR-17
我有这个查询,我可以针对每个小组制作连续几天的小组,但是我很难适应周末的情况。换句话说,下面的结果理想情况下会显示连续几天的10天。
WITH
groups AS (
SELECT
ROW_NUMBER() OVER (ORDER BY action_date) AS rn,
action_date -ROW_NUMBER() OVER (ORDER BY action_date) AS grp,
action_date
FROM test_job_list
WHERE job_id = 164354
)
SELECT count(*) AS num_consec_dates,
min(action_date) AS earliest,
max(action_date) AS latest
FROM groups
group by grp
ORDER BY num_consec_dates desc, earliest desc
NUM_CONSEC
DATES EARLIEST LATEST
---------- --------- ---------
5 20-FEB-17 24-FEB-17
5 13-FEB-17 17-FEB-17
1 10-FEB-17 10-FEB-17
答案 0 :(得分:2)
您可以确定它正在使用的星期几(星期一= 0,星期日= 6):
TRUNC( action_date ) - TRUNC( action_date, 'IW' )
然后,使用LAG
分析函数,您可以比较前一个条目是否是前一个工作日,并使用它来确定该组:
Oracle安装程序:
CREATE TABLE test_job_list ( JOB_ID, W, ACTION_DATE ) AS
SELECT 164354, 'H', DATE '2017-02-10' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-13' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-14' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-15' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-16' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-17' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-20' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-21' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-22' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-23' FROM DUAL UNION ALL
SELECT 164354, 'H', DATE '2017-02-24' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-01' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-02' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-03' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-06' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-07' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-08' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-10' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-13' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-14' FROM DUAL UNION ALL
SELECT 214325, 'H', DATE '2017-03-15' FROM DUAL;
<强>查询强>:
SELECT job_id,
MIN( action_date ) AS start_date,
MAX( action_date ) AS end_date,
COUNT( 1 ) AS num_days
FROM (
SELECT job_id,
action_date,
SUM( has_changed_group ) OVER ( PARTITION BY job_id ORDER BY action_date )
AS group_id
FROM (
SELECT job_id,
action_date,
CASE WHEN
LAG( action_date ) OVER ( PARTITION BY job_id ORDER BY action_date )
= action_date - CASE TRUNC( action_date ) - TRUNC( action_date, 'IW' )
WHEN 0 THEN 3 ELSE 1 END
THEN 0
ELSE 1
END AS has_changed_group
FROM test_job_list
)
)
GROUP BY job_id, group_id
-- HAVING COUNT(1) >= 10;
<强>输出强>:
JOB_ID START_DATE END_DATE NUM_DAYS
---------- ------------------- ------------------- ----------
164354 2017-02-10 00:00:00 2017-02-24 00:00:00 11
214325 2017-03-10 00:00:00 2017-03-15 00:00:00 4
214325 2017-03-01 00:00:00 2017-03-08 00:00:00 6
<强>替代强>:
如果您只想要从未连续10个工作日的工作,那么您可以使用COUNT()
分析函数并指定RANGE
窗口:
SELECT job_id
FROM (
SELECT job_id,
COUNT( 1 ) OVER ( PARTITION BY job_id
ORDER BY action_date
RANGE BETWEEN INTERVAL '13' DAY PRECEDING
AND INTERVAL '0' DAY FOLLOWING )
AS num_days
FROM test_job_list
)
GROUP BY job_id
HAVING MAX( num_days ) < 10;
<强>输出强>:
JOB_ID
----------
214325
答案 1 :(得分:1)
修改2
第一个版本有很多问题,这个问题应该有效。
一个选项是在job_id上将表连接到自身,并在右侧仅过滤左侧日期之前两周的行。然后你可以计算重新定位日期。
select JOB_ID
from (
select g1.JOB_ID, count(g2.ACTION_DATE) CNT
from GROUPS g1
join GROUPS g2
on g1.JOB_ID = g2.JOB_ID
where g2.ACTION_DATE between g1.ACTION_DATE - 13 and g1.ACTION_DATE
group by g1.JOB_ID, g1.ACTION_DATE
) t1
group by JOB_ID
having max(CNT) < 10
答案 2 :(得分:0)
10天=整整2周。对于 11 天,您可以查看14天前的日期,看看它是否恰好是两周前:
select tjl.*,
lag(action_date, 10) over (partition by job id order by action_date) as minad_2weeks
from test_job_list;
一个简单的技巧可以工作10天:
然后,您可以使用聚合来获得没有这段时间的工作:
select job_id
from (select tjl.*,
lag(action_date, 9) over (partition by job_id order by action_date) as lag9_ad
from test_job_list tjl
) tjl
group by job_id
having max(action_date - lag9_ad) > action_date - 14;
也就是说,如果第9个日期回溯在过去两周内,则有两个完整的日期。
答案 3 :(得分:0)
我知道这个解决方案太长了,但你可以通过逐步执行来查看有关查询的所有细节
create table calendar1 as
select day_id,WEEK_DAY_SHORT,day_num_of_week from VITDWH.DW_MIS_TAKVIM as calendar order by day_id;
CREATE TABLE JOB_LIST (JOB_ID NUMBER,ACTION_DATE DATE);
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('10-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('13-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('14-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('15-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('16-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('17-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('20-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('21-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('22-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('23-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(164354,TO_DATE('24-FEB-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('01-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('02-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('03-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('06-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('07-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('08-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('10-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('13-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('14-MAR-17','DD-MON-YY'));
INSERT INTO JOB_LIST VALUES(214325,TO_DATE('15-MAR-17','DD-MON-YY'));
COMMIT;
with a1 as
(
select A.JOB_ID,A.ACTION_DATE,B.DAY_ID,
(case when action_date is not null and lag(action_date) over(partition by job_id order by day_id) is null then action_date else null end) start_date,
(case when action_date is not null and lead(action_date) over(partition by job_id order by day_id) is null then action_date else null end) max_date
from
(
select * from calendar1
WHERE DAY_ID >=(select MIN(ACTION_DATE) from JOB_LIST)
AND DAY_ID <= (select MAX(ACTION_DATE) from JOB_LIST)
ORDER BY DAY_ID
)
B LEFT OUTER JOIN
JOB_LIST A
PARTITION BY (A.JOB_ID) ON (A.ACTION_DATE= B.DAY_ID)
ORDER BY A.JOB_ID,DAY_ID
)
,a2 as
(
select * from a1 where start_date is not null or max_date is not null
)
,a3 as
(
select a2.*,lead(max_date) over(partition by job_id order by day_id) end_date
from a2
)
select a.job_id,a.start_date,nvl(a.maX_date,a.end_date) end_date, (nvl(a.maX_date,a.end_date) -a.start_date) +1 date_count
from a3 a where start_date is not null;