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

連続する日付の有効期間を結合する

    これはギャップと島の問題です。それにアプローチするさまざまな方法があります。これはleadを使用します およびlag 分析関数:

    select distinct product,
      case when start_date is null then lag(start_date)
        over (partition by product order by rn) else start_date end as start_date,
      case when end_date is null then lead(end_date)
        over (partition by product order by rn) else end_date end as end_date
    from (
      select product, start_date, end_date, rn
      from (
        select t.product,
          case when lag(end_date)
              over (partition by product order by start_date) is null
            or lag(end_date)
              over (partition by product order by start_date) != start_date - 1
            then start_date end as start_date,
          case when lead(start_date)
              over (partition by product order by start_date) is null
            or lead(start_date)
              over (partition by product order by start_date) != end_date + 1
            then end_date end as end_date,
          row_number() over (partition by product order by start_date) as rn
        from t
      )
      where start_date is not null or end_date is not null
    )
    order by start_date, product;
    
    PRODUCT START_DATE END_DATE
    ------- ---------- ---------
    A       01-JUL-13  30-SEP-13 
    B       01-OCT-13  30-NOV-13 
    A       01-DEC-13  31-MAR-14 
    

    SQLフィドル

    最も内側のクエリは、製品の前後のレコードを調べ、レコードが連続していない場合にのみ開始時刻や終了時刻を保持します。

    select t.product,
      case when lag(end_date)
          over (partition by product order by start_date) is null
        or lag(end_date)
          over (partition by product order by start_date) != start_date - 1
        then start_date end as start_date,
      case when lead(start_date)
          over (partition by product order by start_date) is null
        or lead(start_date)
          over (partition by product order by start_date) != end_date + 1
        then end_date end as end_date
    from t;
    
    PRODUCT START_DATE END_DATE
    ------- ---------- ---------
    A       01-JUL-13            
    A                            
    A                  30-SEP-13 
    A       01-DEC-13            
    A                            
    A                            
    A                  31-MAR-14 
    B       01-OCT-13            
    B                  30-NOV-13 
    

    次のレベルのselectは、両方の日付が内部クエリによって空白にされた中間期間のものを削除します。これにより、次のようになります。

    PRODUCT START_DATE END_DATE
    ------- ---------- ---------
    A       01-JUL-13            
    A                  30-SEP-13 
    A       01-DEC-13            
    A                  31-MAR-14 
    B       01-OCT-13            
    B                  30-NOV-13 
    

    次に、外側のクエリはそれらの隣接するペアを折りたたみます。重複を作成してからdistinctで削除するという簡単なルートを使用しました 、ただし、両方の値を行のペアの1つに入れ、両方の値をもう1つのnullのままにして、別のselectレイヤーでそれらを削除するなど、他の方法で行うこともできますが、ここでは区別しても問題ないと思います。

    >

    実際のユースケースに日付だけでなく時間が含まれている場合は、内部クエリで比較を調整する必要があります。 +/- 1ではなく、おそらく1秒の間隔、または必要に応じて1/86400ですが、値の精度によって異なります。



    1. SQL Server /SybaseDateDiffと同等のOracle

    2. 重複した結果を与えるクエリ?

    3. csvファイルからデータを取得してmysqlでgrailsに保存する方法は?

    4. CakePHPデータベース接続Mysqlが見つからないか、作成できませんでした