Определите столбцы, в которых значение изменилось по сравнению с предыдущей версией - PullRequest
0 голосов
/ 25 июня 2018

У меня есть таблица, где значения в определенных столбцах могут меняться. Мое требование состоит в том, чтобы определить элементы (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. Любая помощь будет оценена

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

Ваше решение требует трех частей.

  1. Вам необходимо определить порядок изменений. В вашем примере это «сверху вниз». В вашей таблице, скорее всего, у вас будет столбец даты или числовой идентификатор.

  2. Как подсказывает @Aleksej, вы можете получить доступ к предыдущему значению с помощью LAG(value) OVER (... ORDER BY ...)

  3. Вам нужна функция сравнения, которая правильно обрабатывает значения NULL. Это немного больно, и есть больше решений, ни одно из которых не приятно. Я бы порекомендовал DECODE(old_value, new_value, 0, 1)=1, см. здесь для других примеров.

Я добавил несколько дополнительных строк в вашу таблицу, чтобы проверить изменения, включающие значения 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

Пожалуйста, не 3-я строка, когда значение 3 изменилось с 'T' на NULL. Правильно сообщается, но только с новым значением NULL.

0 голосов
/ 25 июня 2018

Это может быть способ, предполагая, что вам нужно упорядочить свои записи по некоторому столбцу (я добавил столбец 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

Используется лаг чтобы получить значение в предыдущей строке (упорядоченное по row_num) для того же ID, а затем просто проверяет, есть ли хотя бы одно различие.

С вашими примерами данных это

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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...