Oracle SQL - 查找历史记录表中列更改的最新数据

时间:2014-07-03 18:29:24

标签: sql oracle window

我正在尝试查找某个列的值与之前状态不同的最新日期或版本。

以下是我的历史记录表的示例:

ID_OF_THING  VERSION_NUMBER   DATA
1            3                'Value2'
1            2                'Value2'
1            1                'Value1'
2            3                'Value3'
2            2                'Value2'
2            1                'Value1'

在这种情况下,id_of_thing 1的答案是版本2,因为它是先前版本号具有不同数据的最高版本号。 id_of_thing 2的答案是版本3。

我不确定如何开始这里。如果我只想要最新的版本号,那就简单如下:

select ID_OF_THING, MAX(VERSION_NUMBER)
GROUP BY ID_OF_THING;

2 个答案:

答案 0 :(得分:1)

这最容易通过分析(aka窗口)函数完成,在这种情况下,使用lead()或lag()查看下一行或上一行的数据。以下内容适合您(将我使用的表名(" test")替换为您所称的表):

select 
    id_of_thing, 
    version_with_latest_change=max(version_number) 
from (
    select 
        id_of_thing, version_number, data, 
        previous_data=lag(data) over (
            partition by id_of_thing 
            order by version_number
        ) 
    from test
) x
where data <> previous_data
group by id_of_thing

答案 1 :(得分:0)

请参阅下面的示例,其中我使用WITH语句来“模拟”您的表。实际上只需用表名替换“tbL”并删除WITH子句。

查询查找值更改的最大版本,并使用id和版本从表中返回行。它还处理只有一个版本的记录没有任何更新的情况。

    WITH tbl As
    (
    SELECT 1 As id, 3 As ver, 'Value2' As val FROM dual UNION ALL
    SELECT 1 As id, 2 As ver, 'Value2' As val FROM dual UNION ALL
    SELECT 1 As id, 1 As ver, 'Value1' As val FROM dual UNION ALL
    SELECT 2 As id, 3 As ver, 'Value3' As val FROM dual UNION ALL
    SELECT 2 As id, 2 As ver, 'Value2' As val FROM dual UNION ALL
    SELECT 2 As id, 1 As ver, 'Value1' As val FROM dual
    )
    SELECT t.*
      FROM tbl t
     WHERE (t.id, t.ver) IN 
    (
    SELECT z.id
         , MAX(z.ver) As max_ver
      FROM ( SELECT x.id
                  , x.ver
                  , x.val
                  , LAG(x.val) OVER (PARTITION BY x.id ORDER BY ver) As lag_val
                  , MIN(x.ver) OVER (PARTITION BY x.id) As min_ver
                  , MAX(x.ver) OVER (PARTITION BY x.id) As max_ver
               FROM tbl x
           ) z
     WHERE ( (z.min_ver = z.max_ver) -- where there is only one version
          OR (z.val != z.lag_val)    -- where the value has changed
           )
     GROUP BY z.id
    );