您的解决方案需要三个部分。
您需要定义更改的顺序。在您的示例中,它是“从上到下”。在您的表格中,您可能会有一个日期列或数字 ID。
正如@Aleksej 建议的那样,您可以使用LAG(value) OVER (... ORDER BY ...) 访问之前的值
您需要一个比较函数,它可以正确处理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。