2016-09-14 49 views
0

我們有一個Oracle SQL查詢來標識表列的值從一個記錄更改爲另一個記錄的位置。相關的數據列是(ID,SOME_COLUMN,FROM_DATE,TO_DATE),其中ID不是唯一的,並且FROM_DATE和TO_DATE確定的時間間隔這對於該ID的特定行是有效的,即使用LAG/LEAD分析函數優化自我加入Oracle SQL查詢?

(ID1, VAL1, 01/01/2016, 03/01/2016) 
(ID1, VAL2, 04/01/2016, 09/01/2016) 
(ID1, VAL3, 10/01/2016, 19/01/2016) 

我們可以實現這個使用下面的自聯接

SELECT N.ID 
     O.SOME_COLUMN OLD_VALUE, 
     N.SOME_COLUMN NEW_VALUE 
FROM OUR_TABLE N, OUR_TABLE O 
WHERE N.ID = O.ID 
    AND N.FROM_DATE - 1 = O.TO_DATE 
    AND N.SOME_COLUMN <> O.SOME_COLUMN 

但是因爲表中包含100百萬的記錄,它相當擊中性能。有沒有更有效的方法來做到這一點?有人暗示了分析功能(例如LAG),但我們目前還找不到解決方案。任何想法,將不勝感激

+0

你的問題不清楚。你的日期根本不重疊,並且你不清楚你想要的結果。 –

+0

日期確實不重疊,它們表示時間間隔,在此期間屬於該ID的特定表格行有效。正如您在示例中看到的,間隔的FROM_DATE始終+1添加到上一個間隔的TO_DATE。我們需要結果,其中SOME_COLUMN的值已經從一個間隔改變到另一個間隔。實際上檢查你的下面的答案,你似乎已經正確解釋了一切。 – hammerfest

回答

2

是的,你可以使用LEAD()獲取最後一個值:

SELECT t.id, 
     t.some_column as OLD_VALUE, 
     LEAD(t.some_column) OVER(PARTITION BY t.id ORDER BY t.from_date) as NEW_VALUE 
FROM YourTable t 

如果你只想要改變,另一個選擇將它包裝和過濾OLD_VALUE <> NEW_VALUE

1

如果你想舊值並在單個行的新值,然後使用lag()

select t.*, 
     lag(some_column) over (partition by id order by from_date) as prev_val 
from t; 

如果值可能不會改變(如建議由您的示例查詢編輯):

select t.* 
from (select t.*, 
      lag(some_column) over (partition by id order by from_date) as prev_val 
     from t 
    ) t 
where prev_val <> some_column; 
1

我認爲這是您談論的LAG()方法。

SELECT * 
    FROM (
    SELECT ID 
      N.SOME_COLUMN NEW_VALUE, 
      N.FROM_DATE, 
      lag(N.SOME_COLUMN) over (partition by N.ID order by FROM_DATE) OLD_VALUE, 
      lag(N.TO_DATE) over (partition by N.ID order by FROM_DATE) OLD_TO_DATE, 
    FROM OUR_TABLE N 
) T 
WHERE FROM_DATE - 1 = OLD_TO_DATE 
    AND NEW_VALUE<> OLD_VALUE; 
+1

謝謝。三個幾乎相同的答案中的第一個,我在這裏放置了接受標記。 – hammerfest

+0

@hammerfest。 。 。其實這是第三個答案。根據你的推理,你應該接受薩吉的答案。如果將鼠標懸停在名稱上方的「時間」(現在說「2小時前回答」),您將看到答案的確切時間。 –

+0

看起來你是對的,在嘗試解決方案並返回到問題頁面後,我簡單地錯誤地回答了兩個答案。我現在改變了接受標記。 @vercelli:對不起,你的回答也是正確的,但它確實不是第一個。 – hammerfest