sql >> データベース >  >> RDS >> Oracle

キーによって日付範囲の行を生成する方法

    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)
    

    出力/計算する属性を定義します。この場合、名前、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

    p.s.接続するには、次のような操作を行う必要があります:

    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である行を除外します。

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



    1. hibernateを使用したスト​​アドプロシージャを介して複数のテーブルエンティティを取得できません

    2. postgresqlエラーPANIC:有効なチェックポイントレコードを見つけることができませんでした

    3. PHPでMySQLを検索し、同じページに結果を表示します

    4. SQLDROPTABLEステートメントとさまざまなユースケース