【问题标题】:Identify the columns where the value changed from previous version确定值从先前版本更改的列
【发布时间】:2018-06-25 09:09:43
【问题描述】:

我有一个表格,其中某些列中的值可以更改。我的要求是识别值已更改的项目(id)。例如

输入:

ID  VALUE1  VALUE2  VALUE3
1    A       B       C
1    X       B       C
2    D       E       F
2    D       E       F
3    G       H       I
3    S       H       T

需要输出:

ID  VALUE1  VALUE2  VALUE3
1   X       
3   S               T

我正在使用 Oracle SQL。任何帮助将不胜感激

【问题讨论】:

标签: oracle oracle11g


【解决方案1】:

这可能是一种方法,假设您需要按某个列对记录进行排序(我添加了一个 row_num 列只是为了解释):

select *
from (
    select ID, 
           case when lag(value1) over (partition by ID order by row_num) != value1 then value1 end as value1,
           case when lag(value2) over (partition by ID order by row_num) != value2 then value2 end as value2,
           case when lag(value3) over (partition by ID order by row_num) != value3 then value3 end as value3
    from yourTable
    )
where value1 is not null
   or value2 is not null
   or value3 is not null

这使用lag 来获取相同ID 的前一行(按row_num 排序)中的值,然后简单地检查是否至少存在一个差异。

有了你的样本数据,这个

with yourTable(row_num, ID, VALUE1, VALUE2, VALUE3) as (
    select 1, 1, 'A', 'B', 'C' from dual union all
    select 2, 1, 'X', 'B', 'C' from dual union all
    select 3, 2, 'D', 'E', 'F' from dual union all
    select 4, 2, 'D', 'E', 'F' from dual union all
    select 5, 3, 'G', 'H', 'I' from dual union all
    select 6, 3, 'S', 'H', 'T' from dual 
)
select *
from (
    select ID, 
           case when lag(value1) over (partition by ID order by row_num) != value1 then value1 end as value1,
           case when lag(value2) over (partition by ID order by row_num) != value2 then value2 end as value2,
           case when lag(value3) over (partition by ID order by row_num) != value3 then value3 end as value3
    from yourTable
    )
where value1 is not null
   or value2 is not null
   or value3 is not null  

给予

        ID VALUE1 VALUE2 VALUE3
---------- ------ ------ ------
         1 X                   
         3 S             T     

2 rows selected.

【讨论】:

  • 感谢 Aleksej.. 将尝试提供的解决方案并提供反馈。
【解决方案2】:

您的解决方案需要三个部分。

  1. 您需要定义更改的顺序。在您的示例中,它是“从上到下”。在您的表格中,您可能会有一个日期列或数字 ID。

  2. 正如@Aleksej 建议的那样,您可以使用LAG(value) OVER (... ORDER BY ...) 访问之前的值

  3. 您需要一个比较函数,它可以正确处理NULL 值。这有点痛苦,还有更多的解决方案,没有一个是好的。我推荐DECODE(old_value, new_value, 0, 1)=1,其他示例请参见here

我在您的表中添加了一些额外的行来测试涉及 NULL 值的更改:

CREATE TABLE mytable (id NUMBER, value1 VARCHAR2(1), value2 VARCHAR2(1), value3 VARCHAR2(1), t TIMESTAMP DEFAULT SYSTIMESTAMP);
INSERT INTO mytable (id,value1,value2,value3) VALUES (1, 'A','B','C');
INSERT INTO mytable (id,value1,value2,value3) VALUES (1, 'X','B','C');
INSERT INTO mytable (id,value1,value2,value3) VALUES (2, 'D','E','F');
INSERT INTO mytable (id,value1,value2,value3) VALUES (2, 'D','E','F');
INSERT INTO mytable (id,value1,value2,value3) VALUES (3, 'G','H','I');
INSERT INTO mytable (id,value1,value2,value3) VALUES (3, 'S','H','T');
INSERT INTO mytable (id,value1,value2,value3) VALUES (3, 'S','H',NULL);
INSERT INTO mytable (id,value1,value2,value3) VALUES (3, 'S','H',NULL);
INSERT INTO mytable (id,value1,value2,value3) VALUES (3, 'S','U','T');


SELECT ID,
       CASE WHEN value1_changed=1 THEN value1 END AS value1, 
       CASE WHEN value2_changed=1 THEN value2 END AS value2,
       CASE WHEN value3_changed=1 THEN value3 END AS value3,
       value1_changed,
       value2_changed,
       value3_changed
  FROM (
        SELECT id, value1, value2, value3,
               DECODE(value1, LAG(value1) OVER (PARTITION BY ID ORDER BY t), 0, 1) value1_changed,       
               DECODE(value2, LAG(value2) OVER (PARTITION BY ID ORDER BY t), 0, 1) value2_changed,
               DECODE(value3, LAG(value3) OVER (PARTITION BY ID ORDER BY t), 0, 1) value3_changed,
               row_number() OVER (PARTITION BY ID ORDER BY t) AS r, t
          FROM mytable
       ) 
 WHERE r > 1
   AND value1_changed + value2_changed + value3_changed >= 0;


ID  value1 value2 value3  changed1 changed2 changed3
 1  X                     1        0        0
 3  S             T       1        0        1
 3                        0        0        1
 3                U       0        0        1

当 value3 从 'T' 变为 NULL 时,请不要在第 3 行。它被正确报告,但只有它的新值 NULL。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-27
    • 2019-11-28
    • 1970-01-01
    • 2012-01-18
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多