0

どこからクエリを開始すればよいかよくわかりませんが、TEST_A と TEST_B の 2 つのテーブルがあります。

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関数が頭に浮かびますが、適切に書き留める方法がわかりません。ありがとう。

追加: ストアド プロシージャがこれを処理する柔軟性を提供する場合、それは依然として受け入れられるソリューションです。

4

1 に答える 1

1

パイプライン化された関数アプローチ (結果を表示するためだけに、ここに別のロット 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>
于 2012-11-06T17:03:22.500 に答える