【问题标题】:Optimize self-join Oracle SQL query with LAG/LEAD analytic functions?使用 LAG/LEAD 分析函数优化自联接 Oracle SQL 查询?
【发布时间】:2016-09-14 11:12:36
【问题描述】:

我们有一个 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),但到目前为止我们还没有找到可行的解决方案。任何想法将不胜感激

【问题讨论】:

  • 你的问题不清楚。您的日期完全不重叠,并且不清楚您想要什么结果。
  • 日期确实不重叠,它们代表时间间隔,在此期间属于该 ID 的特定表行有效。正如您在示例中看到的,一个时间间隔的 FROM_DATE 总是与前一个时间间隔的 TO_DATE 相加 +1。我们需要结果,其中 SOME_COLUMN 的值已从一个间隔更改为另一个。实际上检查您的以下答案,您似乎已经正确解释了所有内容。

标签: sql oracle oracle11g sqlperformance


【解决方案1】:

是的,您可以使用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 &lt;&gt; NEW_VALUE 包装它

【讨论】:

    【解决方案2】:

    如果要将旧值和新值放在一行中,请使用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;
    

    【讨论】:

      【解决方案3】:

      我认为这就是您所说的 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;
      

      【讨论】:

      • @hammerfest 。 . .实际上,这是第三个答案。按照你的推理,你应该接受Sagi的回答。如果您将鼠标悬停在名称上方的“时间”(现在显示“2 小时前已回答”)上,您将看到回答的确切时间。
      • 看来你是对的,我只是在尝试了解决方案并返回问题页面后错误地更改了两个答案。我现在已经更改了接受标记。 @vercelli:对不起,你的回答也一样正确,但确实不是第一个。
      猜你喜欢
      • 1970-01-01
      • 2014-07-16
      • 1970-01-01
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-12
      • 1970-01-01
      相关资源
      最近更新 更多