2016-06-29 3 views
0

1つのOracleデータベーステーブルに格納されたデータを分析する必要があります。このテーブルの例の行は、次のようになります。分析関数を使用して最初の連続する日付を見つける

Department Date Status 
------------------------------------ 
D1   2016/6/1 1 
D1   2016/5/31 0 
D1   2016/5/30 0 
D1   2016/5/29 1 
D1   2016/5/28 0 
D1   2016/5/27 1 
D2   2016/6/1 0 
D2   2016/5/31 1 
D2   2016/5/30 1 
D2   2016/5/29 0 
D2   2016/5/28 0 
D2   2016/5/27 1 

各部門と各日付に1つの行があります。私が欲しいのは、各部門の任意の日付について、この日付より前にStatusが0である最初の日付を見つけることです。たとえば、部門D1の場合は2016/6/1、結果は2015/5/30、D1の場合は2016/5/31、5/30の場合は2015/5/30となります。 D1、2016/5/29および5/28については、2016/5/28です。

結果をSELECT結果として出力し、別のテーブルに格納する必要があります。したがって、結果表は元の表とまったく同じ数の行を持ちます。結果表にはおそらく3つの列があります:DepartmentDateTargetDate

SQL/PL SQLの経験はほとんどありません。私は分析関数とウィンドウ処理を使うべきだと思いますが、本当にクエリを思いつくことはできません。助けてください。ありがとうございました!

+0

分析機能は正しいですが(ウィンドウ処理)、最初に要件を明確にしてください。 D2と2016/5/27の望ましい結果は何ですか?つまり、ある部門の最も古い行がステータス1(またはより一般的には、ゼロとは異なる)を持つ場合はどうなりますか? ....と実際に待って、ステータスが0であるが、あなたの例では、D1と5/29と5/28の日付では、結果は5/27でなければならないと言っていますが、5/27はステータス1 。 どうか明らかにしてください。 (できれば、あなたの投稿をコメントで編集することによって)。 – mathguy

+0

@mathguyコメントありがとうございました。 1)最も古い行がステータス1を持つか、またはゼロとは異なる場合、 'TargetDate'はヌルでなければなりません。その日付の前にステータス0の日付が見つからないことを意味します。 D1と5/29、5/28については、結果は2016/5/28でなければなりません。それはタイプミスでした。私はすでに元の投稿でそれを修正しました。 – tete

+0

クール、ありがとう。私が要件を理解していることを確認するためのもう1つの質問。毎日のように、ステータスがゼロの最新の日付(ステータスがゼロの場合は日付自体、または最初のゼロが見つかるまでは履歴に戻っている可能性があります)に移動します。次に、ステータスゼロの最新の日付を選択しないでください。むしろ、ステータスゼロの連続した日のシーケンスの一部である場合は、その連続シーケンスから最も古い日付を選択します。そのため、6/1、5/31、5/30の回答はD1の5/30です。右?そうであれば、これはいわゆる「タブビトサン」法の応用である。 – mathguy

答えて

3
with test_data (department, date_, status) as (
     select 'D1', date '2016-06-01', 1 from dual union all 
     select 'D1', date '2016-05-31', 0 from dual union all 
     select 'D1', date '2016-05-30', 0 from dual union all 
     select 'D1', date '2016-05-29', 1 from dual union all 
     select 'D1', date '2016-05-28', 0 from dual union all 
     select 'D1', date '2016-05-27', 1 from dual union all 
     select 'D2', date '2016-06-01', 0 from dual union all 
     select 'D2', date '2016-05-31', 1 from dual union all 
     select 'D2', date '2016-05-30', 1 from dual union all 
     select 'D2', date '2016-05-29', 0 from dual union all 
     select 'D2', date '2016-05-28', 0 from dual union all 
     select 'D2', date '2016-05-27', 1 from dual 
    ), 
    t (department, date_, status, lagged_status) as (
     select department, date_, status, 
       lag(status) over (partition by department order by date_) 
     from test_data 
    ) 
select department, date_, 
     max(case when status = 0 and (lagged_status = 1 or lagged_status is null) 
        then date_ end) 
      over (partition by department order by date_ 
        rows between unbounded preceding and current row) as target_date 
from  t 
order by department, date_ desc 
; 

結果:

DEPARTMENT DATE_  TARGET_DATE 
----------- ---------- ----------- 
D1   2016-06-01 2016-05-30 
D1   2016-05-31 2016-05-30 
D1   2016-05-30 2016-05-30 
D1   2016-05-29 2016-05-28 
D1   2016-05-28 2016-05-28 
D1   2016-05-27 (null) 
D2   2016-06-01 2016-06-01 
D2   2016-05-31 2016-05-28 
D2   2016-05-30 2016-05-28 
D2   2016-05-29 2016-05-28 
D2   2016-05-28 2016-05-28 
D2   2016-05-27 (null) 

12 rows selected. 

注意してください、「日」はOracleのキーワードで、列名として使用すべきではありません。代わりにdate_を使用しました(私はアンダースコアを追加しました)。

+0

これは正しい答えだと思います。どうもありがとうございました! – tete

関連する問題