2

次のクエリに問題があります。

SELECT
    B.EMPLOYEE_NAME,
    A.START_DATE+(LEVEL-1) AS INDIVIDUAL_DAY,
    TO_CHAR(A.START_DATE,'MM/DD/YYYY') START_DATE,
    TO_CHAR(A.END_DATE,'MM/DD/YYYY') END_DATE
FROM table1 A
INNER JOIN table2 B ON A.EMPLOYEE_NAME = B.EMPLOYEE_NAME
CONNECT BY LEVEL-1 <= (A.END_DATE-A.START_DATE);

テーブル A にレコードが 1 つしかない場合、探しているものが正確に得られます。ただし、複数のレコードがある場合、過剰な結果が得られます。

私が探しているもの:

EMPLOYEE_NAMESTART_DATE、およびEND_DATEフィールドを持つ行を持つテーブルがあります。この 1 行の情報を複数の行に変換したいと考えています。例:

現時点の -

NAME          START       END
DAVID SMITH   1-1-2001    1-6-2011
JOHN SMITH    2-7-2012    2-9-2012

希望 -

NAME          DATE
DAVID SMITH   1-1-2001
DAVID SMITH   1-2-2001
DAVID SMITH   1-3-2001
DAVID SMITH   1-4-2001
DAVID SMITH   1-5-2001
DAVID SMITH   1-6-2001
JOHN SMITH    2-7-2012
JOHN SMITH    2-8-2012
JOHN SMITH    2-9-2012

これを達成する方法についてのアイデアはありますか? 注: Oracle 10 および 11 を使用しています。

4

2 に答える 2

3

10g / 11gでは、これにモデル句を使用できます。

SQL> with emps as (select rownum id, name, start_date,
  2                       end_date, trunc(end_date)-trunc(start_date) date_range
  3                  from table1)
  4  select name, the_date
  5    from emps
  6  model partition by(id as key)
  7        dimension by(0 as f)
  8        measures(name, start_date, cast(null as date) the_date, date_range)
  9        rules (the_date [for f from 0 to date_range[0] increment 1]  = start_date[0] + cv(f),
 10               name[any] = name[0]);

NAME        THE_DATE
----------- ----------
DAVID SMITH 01-01-2001
DAVID SMITH 01-02-2001
DAVID SMITH 01-03-2001
DAVID SMITH 01-04-2001
DAVID SMITH 01-05-2001
DAVID SMITH 01-06-2001
JOHN SMITH  02-07-2012
JOHN SMITH  02-08-2012
JOHN SMITH  02-09-2012

9 rows selected.

つまり、基本クエリ:

select rownum id, name, start_date,
       end_date, trunc(end_date)-trunc(start_date) date_range
  from table1

日付と範囲を定義するだけです(私はrownum idを使用しましたが、PKがある場合は、代わりにそれを使用できます。

パーティションは、ID(一意の行)ごとに計算を分割します。

6  model partition by(id as key)

対策:

8        measures(name, start_date, cast(null as date) the_date, date_range)

出力/計算する属性を定義します。この場合、name、start_date、および生成する行の範囲を使用しています。さらに、計算された日付を保持する列the_dateを定義しました(つまり、start_date + nを計算します。ここで、nは0から範囲です。

ルールは、列に入力する方法を定義します。

9        rules (the_date [for f from 0 to date_range[0] increment 1]  = start_date[0] + cv(f),
10               name[any] = name[0]);

だから 

the_date [for f from 0 to date_range[0] increment 1]

date_rangeが保持する行数+1(つまり、合計6つの日付)を生成すると言っています。の値は、 (現在の値)関数fを介して参照できます。cv

したがって、davidの1行目にはがthe_date [0] = start_date+0あり、続いて2行目にはがありthe_date [1] = start_date+1ます。start_date + 5までのすべての方法(つまりend_date

接続するためのpsは、次のようなことを行う必要があります。

select 
    A.EMPLOYEE_NAME,
    A.START_DATE+(b.r-1) AS INDIVIDUAL_DAY,
    TO_CHAR(A.START_DATE,'MM/DD/YYYY') START_DATE,
    TO_CHAR(A.END_DATE,'MM/DD/YYYY') END_DATE
FROM table1 A
     cross join (select rownum r
                   from (select max(end_date-start_date) d from table1)
                  connect by level-1 <= d) b
 where A.START_DATE+(b.r-1) <= A.END_DATE
 order by 1, 2;

つまり、サブクエリへの接続を分離してから、individual_day>end_dateの行を除外します。

しかし、私はこのアプローチをお勧めしません。そのパフォーマンスは、モデルアプローチと比較して悪化します(特に範囲が大きくなる場合)。

于 2013-01-22T23:12:23.043 に答える
3

スコアを求めていません。あなたの投稿を見つけて、退屈でこれをやっています...

私のテストテーブル:

EMPNO    ENAME    START_DATE    END_DATE
------------------------------------------
7369     SMITH    6/1/2011      6/7/2011
7499     ALLEN    7/1/2011      7/3/2011

SELECT ename, ind_start_date
  FROM
  (
   SELECT distinct ename
        , start_date
        , to_char(start_date + (LEVEL-1), 'MM/DD/YYYY') ind_start_date
        , to_char(end_date, 'MM/DD/YYYY') end_date
    FROM emp_test
   WHERE ename IN ('SMITH', 'ALLEN')
  CONNECT BY LEVEL <= (end_date-start_date)+1
  ORDER BY ename
 )
 /

ENAME    IND_START_DATE
--------------------------
ALLEN    07/01/2011
ALLEN    07/02/2011
ALLEN    07/03/2011
SMITH    06/01/2011
SMITH    06/02/2011
SMITH    06/03/2011
SMITH    06/04/2011
SMITH    06/05/2011
SMITH    06/06/2011
SMITH    06/07/2011

複雑にしないでおく...

于 2013-03-14T17:33:16.840 に答える