使用LAG / LEAD分析函数优化自我加入Oracle SQL查询?

时间:2016-09-14 11:12:36

标签: sql oracle oracle11g sqlperformance

我们有一个Oracle SQL查询来识别表列的值从一个记录更改为另一个记录的记录。相关列是(ID,SOME_COLUMN,FROM_DATE,TO_DATE),其中ID不唯一,FROM_DATE和TO_DATE确定该ID的特定行有效的时间间隔,即

(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

然而,由于该表包含1亿条记录,因此它的性能非常好。有没有更有效的方法来做到这一点?有人暗示了分析函数(例如LAG),但到目前为止我们还无法找到一个可行的解决方案。任何想法将不胜感激

3 个答案:

答案 0 :(得分:3)

是的,您可以使用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 :(得分: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;

答案 2 :(得分: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;