2017-06-14 54 views
0

我試圖找出一個更好的方式來實現這一目標:滯後可變偏移或同等解決方案在Oracle

給定一個示例表

DATE PRC_A  PRC_B 
05/17 10   10 
06/17 X   10 
07/17 10   X 
08/17 10   X 
09/17 X   20 

目標:如果從數據缺失PRC_A,但不是從PRC_B,計算從當天和PRC_B前一天的價格差異PRC_B's。如果PRC_B's前一天價格也丟失,請繼續返回日曆,直到找到非空行。

例如:

06/17缺少prc_A所以PRC_B's價格之間的差額將是0。09/17的區別是,因爲可用的之前的數據是06/17。

現在我正在使用LAG函數來計算差異。但是,當前一行也是空的時候,我卡住了。我已經設置了一個計數器,並考慮做一個while循環,但在循環之前應該有一個條件,並且不起作用。我是新來的sql,我不習慣語法和規則。 到目前爲止,這是我的代碼。這是不正確的,但這是我的開始:

​​

那麼我怎麼能實現我的目標?

回答

2

這可以通過普通的SQL簡單而高效地完成 - 不需要過程代碼。

我不確定你想要什麼輸出格式,但你應該能夠適應你的需求。

從你所描述的,你正在尋找LAST_VALUE()功能,而不是LAG()LAST_VALUE()允許您忽略空值。注意窗口子句(ROWS BETWEEN...) - 默認是包含當前行,而您不需要這樣做,所以您必須有明確的窗口子句。

編輯:作爲@boneist在下面評論指出,自從甲骨文11.2 LAG()添加IGNORE NULLS選項的功能 - 它的優點是,默認情況下它會尋找「背」在早先的行,開始了最近 - 所以窗口條款將不再需要。在Oracle 11.2或更高版本中,而不是下面顯示的LAST_VALUE()函數,可以使用LAG(prc_b ignore nulls) over (order by dt)

with 
    test_data (dt, prc_a, prc_b) as (
     select date '2017-05-01', 10, 10 from dual union all 
     select date '2017-06-01', null, 10 from dual union all 
     select date '2017-07-01', 10, null from dual union all 
     select date '2017-08-01', 10, null from dual union all 
     select date '2017-09-01', null, 20 from dual 
    ) 
-- End of test data (not part of the solution). SQL query begins below this line. 
select dt, prc_a, prc_b, 
     case when prc_a is null 
      then prc_b - last_value(prc_b ignore nulls) over (order by dt 
           rows between unbounded preceding and 1 preceding) 
     end as prc_b_diff 
from test_data 
; 

DT    PRC_A  PRC_B PRC_B_DIFF 
---------- ---------- ---------- ---------- 
2017-05-01   10   10   
2017-06-01     10   0 
2017-07-01   10      
2017-08-01   10      
2017-09-01     20   10 
+0

很好解釋!謝謝你給我介紹這個函數 – ana

+0

@mathguy從11g開始,[LAG](https://docs.oracle.com/cloud/latest/db112/SQLRF/functions082.htm#SQLRF00652)/ LEAD也有忽略空功能,所以你可以簡化你的解決方案。 – Boneist

+0

@骨科醫生 - 好點!我從去年開始就一直在學習Oracle,所以我應該知道這一點 - 我只從11.2和12.1的文檔中讀到;因爲我從來不需要這個,所以我從來沒有學過。我將編輯帖子以添加此替代方案。 – mathguy

相關問題