1. 程式人生 > >Oracle求同比SQL

Oracle求同比SQL

計算需求:
1.求原始資料JS.TOPARTYNAME(購電方)的同比增長率

2.求原始資料華東購電(總計)=上海+江蘇+浙江+福建+安徽的同比增長率

分析過程:
1.首先,我們要理解什麼是同比?
同比一般情況下是今年第n月與去年第n月比。同比發展速度主要是為了消除季節變動的影響,
用以說明本期發展水平與去年同期發展水平對比而達到的相對發展速度。如,本期2月比去年2月,本期6月比去年6月等。
那麼,我們求的是同比增長率,其公式見下:

同比增長率=(本期數-同期數)/同期數*100% 指和去年同期相比較的增長率

2.理解同比的基本概念後,我們要知道在Oracle同比的基本求法?

如下圖資料,如何計算改股票的市值同比增長率?


這裡我要介紹下Oracle的Lag函式:
Lag分析函式可以在同一次查詢中取出同一欄位的前N行的資料(Lag)作為獨立的列。
這種操作可以代替表的自聯接,並且LAG有更高的效率。
/*語法*/
lag(exp_str,offset,defval) over()
--exp_str要取的列
--offset取偏移後的第幾行資料
--defval:沒有符合條件的預設值


那麼上圖的股票市值同比增長率,我們可以通過如下SQL實現:

select a.*,
       nvl(round(money / lag(money) over(order by id) * 100, 2) - 100, '0') || '%' as 同比
  from d_temp_data a

結果如下圖


上段SQL中同時使用NVL和Round函式:

NVL函式格式為:

NVL( string1, replace_with)

功能:如果string1為NULL,則NVL函式返回replace_with的值,否則返回string1的值,如果兩個引數都為NULL ,則返回NULL。

Round函式語法:
round(number,digits) 
引數:
number,要四捨五入的數,digits是要小數點後保留的位數
  --如果 digits 大於 0,則四捨五入到指定的小數位。 
  --如果 digits 等於 0,則四捨五入到最接近的整數。 

  --如果 digits 小於 0,則在小數點左側進行四舍五

3.瞭解oracle求同比的基本用法,我們需要具體應用到源是資料查詢中,但是分析原始資料,發現源資料並不是規律連續的,見下圖


那麼這帶來的問題是我們並不能向上面講的那樣簡單的去使用lag函數了,那怎麼辦呢?

想到先整理資料後,再去使用函式分析查詢是一個好辦法,於是有了下方的解決辦法:

A.求原始資料JS.TOPARTYNAME(購電方)的同比增長率

with tb as(
 select to_char(t.t_date, 'YYYY') year, to_char(t.t_date, 'MM') month, t.*
 from TRY_OPT_MON_ELEC_JS t
 where t.FYGZ = 'Z'
   and t.js_elec <> 0
   and t.js_kind in ('四川水電送華東月度1', '四川水電送華東短期2', '四川水電送華東短期3', '四川水電送浙江年度',
        '四川水電送江蘇年度', '三峽送華東', '向家壩送上海交易', '錦東錦西官地送江蘇交易',
        '四川水電送華東短期1', '溪洛渡送浙江', '錦東錦西官地送江蘇交易', '溪洛渡左岸送浙江交易')
)
select max(t.t_date) 日期,
       t.topartyname 購電方,
       t.js_elec 結算電量,
       t.js_kind 結算品種,
       nvl(round(((t.js_elec - (lag(t.js_elec,1) over(partition by t.month, t.topartyname,t.js_kind order by t.year)))
       /((lag(t.js_elec,1) over(partition by t.month, t.topartyname,t.js_kind order by t.year))))*100,2),'0')||'%' as 同比
 from tb t
 where 1=1
 group by t.js_kind,t.topartyname, t.year, t.month, t.js_elec
 order by t.month
思路分析:
1.建立臨時表tb 
2.把t_date日期欄位拆分為年、月兩個欄位方便分組,篩去js_elec(售電量)為零的記錄是,篩去不需要的js_kind(結算品種)
3.使用lag分析函式求得同比值
4.使用round函式格式化兩位小數

5.使用nvl函式滿足空值補零

查詢結果:


B.求原始資料華東購電(總計)=上海+江蘇+浙江+福建+安徽的同比增長率

with tb as(
 select to_char(t.t_date, 'YYYY') year, to_char(t.t_date, 'MM') month, t.*
 from TRY_OPT_MON_ELEC_JS t
   where t.FYGZ = 'Z'
   and t.js_elec <> 0
   and t.js_kind in ('四川水電送華東月度1', '四川水電送華東短期2', '四川水電送華東短期3', '四川水電送浙江年度',
        '四川水電送江蘇年度', '三峽送華東', '向家壩送上海交易', '錦東錦西官地送江蘇交易',
        '四川水電送華東短期1', '溪洛渡送浙江', '錦東錦西官地送江蘇交易', '溪洛渡左岸送浙江交易')
   and t.topartyname in ('上海','江蘇','浙江','福建','安徽')
)
,tb2 as(
select max(t.t_date) t_date, sum(t.js_elec) js_elec, t.year, t.month
from tb t
group by t.year, t.month
)
select max(t.t_date) 日期,
       '華東' 華東,
       t.js_elec 結算電量,
       nvl(round(((t.js_elec - (lag(t.js_elec,1) over(partition by t.month order by t.year)))
       /((lag(t.js_elec,1) over(partition by t.month order by t.year))))*100,2),'0')||'%' as 同比
 from tb2 t
 where 1=1
 group by t.year, t.month, t.js_elec
 order by t.year,t.month
思路分析:
1.建立臨時表tb 
2.把t_date日期欄位拆分為年、月兩個欄位方便分組,篩去js_elec(售電量)為零的記錄是,篩去不需要的js_kind(結算品種)和不是華東區的購電單位
3.使用lag分析函式求得同比值
4.使用round函式格式化兩位小數

5.使用nvl函式滿足空值補零

查詢結果: