Ваше решение требует трех частей.
Вам необходимо определить порядок изменений. В вашем примере это «сверху вниз». В вашей таблице, скорее всего, у вас будет столбец даты или числовой идентификатор.
Как подсказывает @Aleksej, вы можете получить доступ к предыдущему значению с помощью LAG(value) OVER (... ORDER BY ...)
Вам нужна функция сравнения, которая правильно обрабатывает значения 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.