不确定从哪里开始查询,但我有两个表,TEST_A和TEST_B。
TEST_B包含特定ID的特定日期范围,而TEST_A包含具有提供的ASSIGNMENT值的ID的日期范围。
下面是创建和填充表格的DDL。
CREATE TABLE TEST_A
(
ID VARCHAR2(5),
START_DATE DATE,
END_DATE DATE,
ASSIGNMENT VARCHAR2(25)
)
STORAGE (
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
NOMONITORING;
CREATE TABLE TEST_B
(
ID VARCHAR2(5),
START_DATE DATE,
END_DATE DATE
)
STORAGE (
BUFFER_POOL DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
NOMONITORING;
填充表格的脚本:
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('A', TO_DATE('01/01/2010', 'MM/DD/YYYY'), TO_DATE('01/31/2010', 'MM/DD/YYYY'), 'Lot A');
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('A', TO_DATE('02/01/2010', 'MM/DD/YYYY'), TO_DATE('02/15/2010', 'MM/DD/YYYY'), 'Lot A');
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('A', TO_DATE('02/18/2010', 'MM/DD/YYYY'), TO_DATE('02/28/2010', 'MM/DD/YYYY'), 'Lot C');
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('A', TO_DATE('03/01/2010', 'MM/DD/YYYY'), TO_DATE('03/31/2010', 'MM/DD/YYYY'), 'Lot D');
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('B', TO_DATE('08/01/2010', 'MM/DD/YYYY'), TO_DATE('08/31/2010', 'MM/DD/YYYY'), 'Lot E');
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('B', TO_DATE('09/15/2010', 'MM/DD/YYYY'), TO_DATE('09/30/2010', 'MM/DD/YYYY'), 'Lot E');
INSERT INTO TEST_A(ID, START_DATE, END_DATE, ASSIGNMENT)
VALUES('C', TO_DATE('09/15/2010', 'MM/DD/YYYY'), TO_DATE('09/30/2010', 'MM/DD/YYYY'), 'Lot E');
INSERT INTO TEST_B(ID, START_DATE, END_DATE)
VALUES('A', TO_DATE('01/01/2010', 'MM/DD/YYYY'), TO_DATE('12/31/2099', 'MM/DD/YYYY'));
INSERT INTO TEST_B(ID, START_DATE, END_DATE)
VALUES('B', TO_DATE('08/01/2010', 'MM/DD/YYYY'), TO_DATE('12/31/2099', 'MM/DD/YYYY'));
INSERT INTO TEST_B(ID, START_DATE, END_DATE)
VALUES('C', TO_DATE('01/01/2010', 'MM/DD/YYYY'), TO_DATE('12/31/2099', 'MM/DD/YYYY'));
根据数据,我需要通过作业对来自TEST_A的记录进行分组,并填写两者之间的缺失日间隙。每个ID的记录还应涵盖表TEST_B中提供的整个开始和结束日期。为了进一步解释,我需要的结果数据如下所示:
ID START_DATE END_DATE ASSIGNMENT
A 01/01/2010 02/15/2010 Lot A
A 02/16/2010 02/17/2010 {NULL}
A 03/01/2010 03/31/2010 Lot D
A 04/01/2010 12/31/2099 {NULL}
B 08/01/2010 08/31/2010 Lot E
B 09/01/2010 09/14/2010 {NULL}
B 09/15/2010 09/30/2010 Lot E
B 10/01/2010 12/31/2099 {NULL}
C 01/01/2010 09/14/2010 {NULL}
C 09/15/2010 09/30/2010 Lot E
C 10/01/2010 12/31/2099 {NULL}
感谢您为此构建查询的任何帮助。我想到了LAG功能,但我不确定如何正确地将其写下来。感谢。
增加: 如果存储过程将提供处理这个的灵活性,那么这仍然是一个可接受的解决方案。
答案 0 :(得分:1)
一个流水线函数方法(我在这里添加了另一个Lot A(id = A)行以显示结果)。
create type test_typ as object(id varchar2(5),
start_date date,
end_date date,
assignment varchar2(25)
);
/
create type test_tab as table of test_typ;
/
create or replace function test_pipe
return test_tab pipelined is
begin
for r_row in (select a.id, a.start_date, a.end_date,
a.assignment,
lead(a.start_date, 1) over (partition by a.id order by a.start_date) next_start_date,
lead(a.id, 1) over (order by a.id, a.start_date) next_id,
lag(a.id, 1) over (order by a.id, a.start_date) prior_id,
b.start_date min_start, b.end_date max_end
from (select id, min(start_date) start_date, max(end_date) end_date, assignment
from (select id, start_date, end_date, assignment, rn, max(rn) over (partition by id order by start_date) r
from (select id, start_date, end_date, assignment,
case
when lag(end_date, 1) over (partition by id, assignment order by start_date) = start_date-1
then null
else row_number() over (order by start_date)
end rn
from test_a)
order by id, start_date)
group by id, assignment, r) a,
test_b b
where b.id = a.id
order by id, start_date)
loop
if ((r_row.prior_id != r_row.id or r_row.prior_id is null) and r_row.start_date > r_row.min_start)
then
pipe row(test_typ(r_row.id, r_row.min_start, r_row.start_date-1, null));
end if;
pipe row(test_typ(r_row.id, r_row.start_date, r_row.end_date, r_row.assignment));
if (r_row.next_start_date != r_row.end_date + 1)
then
pipe row(test_typ(r_row.id, r_row.end_date + 1, r_row.next_start_date-1, null));
elsif ((r_row.next_id != r_row.id or r_row.next_id is null) and r_row.end_date < r_row.max_end)
then
pipe row(test_typ(r_row.id, r_row.end_date + 1, r_row.max_end, null));
end if;
end loop;
end test_pipe;
有数据:
SQL> select * from test_a order by 1, 2;
ID START_DAT END_DATE ASSIGNMENT
----- --------- --------- -------------------------
A 01-JAN-10 31-JAN-10 Lot A
A 01-FEB-10 15-FEB-10 Lot A
A 18-FEB-10 28-FEB-10 Lot C
A 01-MAR-10 31-MAR-10 Lot D
A 01-APR-10 30-MAY-10 Lot A
B 01-AUG-10 31-AUG-10 Lot E
B 15-SEP-10 30-SEP-10 Lot E
C 15-SEP-10 30-SEP-10 Lot E
SQL> select *
2 from table(test_pipe()) b;
ID START_DAT END_DATE ASSIGNMENT
----- --------- --------- -------------------------
A 01-JAN-10 15-FEB-10 Lot A
A 16-FEB-10 17-FEB-10
A 18-FEB-10 28-FEB-10 Lot C
A 01-MAR-10 31-MAR-10 Lot D
A 01-APR-10 30-MAY-10 Lot A
A 31-MAY-10 31-DEC-99
B 01-AUG-10 31-AUG-10 Lot E
B 01-SEP-10 14-SEP-10
B 15-SEP-10 30-SEP-10 Lot E
B 01-OCT-10 31-DEC-99
C 01-JAN-10 14-SEP-10
C 15-SEP-10 30-SEP-10 Lot E
C 01-OCT-10 31-DEC-99
13 rows selected.
SQL>