2016-04-19 13 views
0

は、私は次のようなデータを持っていると言います。出力は次のようになります。の追加は、累積的に

name year month sale opening bal closing bal 
A  2007  04  5  0    5 
A  2007  05  2  5    7 
B  2008  12  3  12    15 
A  2008  04  0  5    5 -- to be generated 
A  2008  05  0  7    7 -- to be generated 
B  2009  12  56  15    71 
C  2009  08  89  71    160 
A  2009  04  0  5    5 -- to be generated 
A  2009  05  0  7    7 -- to be generated 
B  2016  01  10  278   288 
B  2016  12  0   71    71 -- to be generated 
A  2016  02  8  288   296 
A  2016  04  0   5    5 -- to be generated 
A  2016  05  0   7    7 -- to be generated 
D  2016  03  12  296   308 
E  2016  04  34  308   342 
C  2016  08  0  160   160 -- to be generated 

期首残高は前月の期末残高であり、それは来年の期首残高よりも、来年になった場合、前年度の決算残高です。それはその後の年のようにこれのように働くことができるはずです。私はこの部分が働いている。しかし、私は2008年に存在する2008年に存在する2009年を見逃す方法を知らない。たとえば、A、2008,04、A、2008,05のキーは2009年に存在せず、コードはそれは上記のように2009年です。他の年および月にも同じことが適用されます。

私はOracle 12cで作業しています。

ありがとうございます。

+1

サンプルデータに入力しましたか?あなたの出力データはA、2007、04、05を参照しますが、サンプルデータにはA、2007、04ではなくB、2007、05があります。これは2007年から現在までの年数か、データに存在する年数(例:2007年、2008年、2009年および2016年)ですか? P.S. **提示されたサンプルデータのために**ありがとうございます!この手軽な形式でデータを入手するのは稀です! * {: - D – Boneist

+0

私はどこにB、2007,05を持っていません。S – bytebiscuit

+0

'select 2 id、 'B' name、 '2007' year、 '05' month、デュアルユニオンからの2つの販売すべて – Boneist

答えて

1

これは私があなたの結果に最も近いものですが、それは完全に一致していないことに気付きます。たとえば、期首残高が正しく表示されない(12の開始残高は、id = 3の出力行のどこから来たのか)。とにかく、うまくいけば、次は、必要に応じて修正することができます:私は、私のクエリで(表中sample_dataサブクエリを任意の月と名前の組み合わせをリンクするPartition Outer Joinを使用しました

with sample_data as (select 1 id, 'A' name, '2007' year, '04' month, 5 sales from dual union all 
        select 2 id, 'A' name, '2007' year, '05' month, 2 sales from dual union all 
        select 3 id, 'B' name, '2008' year, '12' month, 3 sales from dual union all 
        select 4 id, 'B' name, '2009' year, '12' month, 56 sales from dual union all 
        select 5 id, 'C' name, '2009' year, '08' month, 89 sales from dual union all 
        select 13 id, 'B' name, '2016' year, '01' month, 10 sales from dual union all 
        select 14 id, 'A' name, '2016' year, '02' month, 8 sales from dual union all 
        select 15 id, 'D' name, '2016' year, '03' month, 12 sales from dual union all 
        select 16 id, 'E' name, '2016' year, '04' month, 34 sales from dual), 
      dts as (select distinct year 
        from sample_data), 
      res as (select sd.name, 
          dts.year, 
          sd.month, 
          nvl(sd.sales, 0) sales, 
          min(sd.year) over (partition by sd.name, sd.month) min_year_per_name_month, 
          sum(nvl(sd.sales, 0)) over (partition by name order by to_date(dts.year||'-'||sd.month, 'yyyy-mm')) - nvl(sd.sales, 0) as opening, 
          sum(nvl(sd.sales, 0)) over (partition by name order by to_date(dts.year||'-'||sd.month, 'yyyy-mm')) as closing 
        from dts 
          left outer join sample_data sd partition by (sd.name, sd.month) on (sd.year = dts.year)) 
select name, 
     year, 
     month, 
     sales, 
     opening, 
     closing 
from res 
where (opening != 0 or closing != 0) 
and year >= min_year_per_name_month 
order by to_date(year||'-'||month, 'yyyy-mm'), 
     name; 

NAME YEAR MONTH  SALES OPENING CLOSING 
---- ---- ----- ---------- ---------- ---------- 
A 2007 04    5   0   5 
A 2007 05    2   5   7 
A 2008 04    0   7   7 
A 2008 05    0   7   7 
B 2008 12    3   0   3 
A 2009 04    0   7   7 
A 2009 05    0   7   7 
C 2009 08   89   0   89 
B 2009 12   56   3   59 
B 2016 01   10   59   69 
A 2016 02    8   7   15 
D 2016 03   12   0   12 
A 2016 04    0   15   15 
E 2016 04   34   0   34 
A 2016 05    0   15   15 
C 2016 08    0   89   89 
B 2016 12    0   69   69 

- あなたがいることを必要はありませんサブクエリ、代わりにあなたのテーブルを使用するだけです!)を同じテーブルの任意の年に設定してから、開始/終了残高を計算します。私は、CTEでのサンプルデータから始まり、開口部と0

+0

hmmありがとうBoneist。私は自分のインスタンスでパーティションを有効にしていません。 Merge Intoクエリの行で何か考えていました。名前、年、月などのキーが2008年に存在していても2009年に存在しない場合は、前述の値で2009年に挿入します。 – bytebiscuit

+0

結合で使用されるパーティション化は、テーブルをパーティション化するために使用されるものと同じではありません**。 AFAIKでは、特定のタイプの結合を使用することにライセンスの影響はありません。 – Boneist

+0

@bytebiscuitテーブルに最初に表示される年の前に値がない月を除外する回答を更新しました – Boneist

1

の開閉バランス@boneistsアプローチのバリエーションを持っている任意の行を破棄:

しかし、あまりにも同じ結果を得る
with t as (
    select 1 id, 'A' name, '2007' year, '04' month, 5 sales from dual union all 
    select 2 id, 'A' name, '2007' year, '05' month, 2 sales from dual union all 
    select 3 id, 'B' name, '2008' year, '12' month, 3 sales from dual union all 
    select 4 id, 'B' name, '2009' year, '12' month, 56 sales from dual union all 
    select 5 id, 'C' name, '2009' year, '08' month, 89 sales from dual union all 
    select 13 id,'B' name, '2016' year, '01' month, 10 sales from dual union all 
    select 14 id,'A' name, '2016' year, '02' month, 8 sales from dual union all 
    select 15 id,'D' name, '2016' year, '03' month, 12 sales from dual union all 
    select 16 id,'E' name, '2016' year, '04' month, 34 sales from dual 
), 
y (year, rnk) as (
    select year, dense_rank() over (order by year) 
    from (select distinct year from t) 
), 
r (name, year, month, sales, rnk) as (
    select t.name, t.year, t.month, t.sales, y.rnk 
    from t 
    join y on y.year = t.year 
    union all 
    select r.name, y.year, r.month, 0, y.rnk 
    from y 
    join r on r.rnk = y.rnk - 1 
    where not exists (
    select 1 from t where t.year = y.year and t.month = r.month and t.name = r.name 
) 
) 
select name, year, month, sales, 
    nvl(sum(sales) over (partition by name order by year, month 
    rows between unbounded preceding and 1 preceding), 0) as opening_bal, 
    nvl(sum(sales) over (partition by name order by year, month 
    rows between unbounded preceding and current row), 0) as closing_bal 
from r 
order by year, month, name; 

あなたの元のデータから、すべての個別の年を生成

NAME YEAR MONTH  SALES OPENING_BAL CLOSING_BAL 
---- ---- ----- ---------- ----------- ----------- 
A 2007 04    5   0   5 
A 2007 05    2   5   7 
A 2008 04    0   7   7 
A 2008 05    0   7   7 
B 2008 12    3   0   3 
A 2009 04    0   7   7 
A 2009 05    0   7   7 
C 2009 08   89   0   89 
B 2009 12   56   3   59 
B 2016 01   10   59   69 
A 2016 02    8   7   15 
D 2016 03   12   0   12 
A 2016 04    0   15   15 
E 2016 04   34   0   34 
A 2016 05    0   15   15 
C 2016 08    0   89   89 
B 2016 12    0   69   69 

y CTE(もっと意味のある名前を使用して自由に感じる!)、またそう、ランキングを追加します。それはまた、問題に予想される結果と一致していません2007年は1、2008年は2、2009年は3、201 6は4です。

r再帰CTEは、前年度の名前/月データに基づいて、売上がゼロのダミー行と実際のデータを結合します。

再帰的なCTEによって生成される累積合計を分析して、開閉残高を追加することができます。これは、ウィンドウング句を使用して、どの販売値を含めるかを決定します。基本的には、開始時点と終了時点の残高はすべてこの時点までのすべての値の合計ですが、現在の行は含まれません。

+0

再帰的なCTEへの分割結合を好むかもしれないと思います。 ;以前はそれを使用していませんでした。実際のデータがたくさんあると、(not-exists節で)自己結合を避けるので、目立って効率的です。 –