2016-04-19 36 views
0

說我有以下數據:添加缺少的從以前的一個月或一年累計數據

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 

我想會逐漸增加了所有在所有年銷售和它們各自的週期(月)。輸出應該如下所示:

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 

期初餘額是前一個月的期末餘額,如果它進入明年比明年的期初餘額是上年年末餘額。在接下來的幾年中,它應該能夠像這樣工作。我有這部分工作。然而,我不知道如何避免2009年存在的缺失。例如,2008年的關鍵A,2008,04以及A,2008,05不存在,代碼應該能夠添加它在2009年如上。其他年份和月份也一樣。

我正在使用Oracle 12c。

在此先感謝。

+1

您是否在樣本數據中存在拼寫錯誤?您的輸出數據引用了A,2007,04和05,但在您的示例數據中,您有A,2007,04,但是B,2007,05。此外,您的「隨後幾年」是什麼意思?這是2007年至今的所有年份,還是僅僅是數據中存在的年份(例如2007年,2008年,2009年和2016年)?附: **感謝您提供的樣品數據!以這種方便的形式獲取數據非常少見! * {: - D – Boneist

+0

我在那裏沒有B,2007,05。自己無法看到:S – bytebiscuit

+0

'select 2 id,'B'name,'2007'year,'05'month,2 sales from dual union all' – Boneist

回答

1

這是最接近我可以得到你的結果,雖然我意識到它不是一個完全匹配。例如,您的期初餘額看起來不正確(12的期初餘額來自id = 3的輸出行的位置)?無論如何,希望下面將讓您酌情修改:

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 

我用Partition Outer Join在表(任何月份和名稱組合鏈接在我的查詢中,子查詢sample_data - 你不會需要一個子查詢,你可以用你的表來代替!)到同一表中的任何年份,然後計算期初/期末餘額。然後,我丟棄有一個開放和0

+0

嗯感謝骨科醫生。我沒有在我的實例中啓用分區。我正在考慮更多合併進入查詢的內容。看看是否有一個關鍵字:姓名,年份,月份在2008年存在,但2009年沒有,然後在2009年將其與所提到的值一起插入。 – bytebiscuit

+0

在連接中使用的分區是**不與用於分區表的分區相同。 AFAIK,使用特定類型的加入沒有許可含義! – Boneist

+0

@bytebiscuit我已經更新了我的答案,排除了在他們首次出現在表中的年份之前沒有值的月份 – Boneist

1

上@boneists方法的變化期末餘額的任何行,開始在CTE示例數據:

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分區連接,現在我已經計算出它在做什麼;之前沒有使用過。如果存在大量真實數據,它也可能顯着更高效,因爲它避免了自聯接(在不存在的子句中)。 –

相關問題