我在审核表(AUDIT_TABLE)中具有以下情形。
t_id e_id detail_log date_created
01 111 USER_1; Salary: from '25' to '30'; Dept_ID: from '001' to ''; 01/01/2019
02 111 USER_1; Dept_ID: from '' to '001'; 01/01/2019
03 001 USER_1; Dept_ID: from '012' to ''; 01/01/2019
04 002 USER_1; Dept_ID: from '555' to '666'; 01/01/2019
05 222 USER_1; Dept_ID: from '' to '123'; 01/02/2019
06 333 USER_1; Salary: from '10' to '20'; Dept_ID: from '200' to ''; 01/03/2019
07 444 USER_1; Salary: from '50' to '100'; Dept_ID: from '' to '10'; 01/04/2019
批处理过程中有一个错误,当“ Dept_ID: from .. to
”值(在另一个表中)没有变化时,触发插入到该审计表并创建这些记录“ Dept_ID
”。这些记录中有数百万需要清除。需要更新具有多个字段更改的记录,即item_id 01
,以清除Dept_ID
:审核消息,而只有Dept_ID
审核记录的记录需要删除({{ 1}})。在其他两个记录中,可能还有其他对仅包含item_id 02
审核消息的对,在这种情况下,都需要删除两者。触发逻辑已得到修复,因此在Dept ID
中没有实际更改时,不再创建更多错误记录,但是需要清除在错误期间已经创建的记录。在某些行中可能存在一对记录,在这种情况下,由于Dept_ID实际上已更改为null或从null更改为值,因此不需要更新/删除这些记录。
因此,在修复以上数据集之后,应该存在以下内容:
Dept ID
我已经准备好执行删除和更新语句,但是如果删除该对中的一条记录,则更新将找不到另一条记录,因为更新语句取决于已删除的记录,反之亦然。我曾想使用merge语句,但不确定如何使用。有什么想法吗?
答案 0 :(得分:2)
所以假设这样的测试数据
DETAIL_LOG
-----------------------------------------------------------------------------------------
USER_1; Salary: from '25' to '30'; Dept_ID: from '001' to '';
USER_1; Dept_ID: from '' to '001';
USER_1; Salary: from '25' to '30'; Dept_ID: from '001' to '002'; Prdeel: from '0' to '1':
USER_1; Dept_ID: from '' to '';
如果我理解正确,您想从第一行和第二行中删除Dept_ID
条目,因为其中一个值为NULL。我添加了带有两个NULL值的行,该行也应删除。
第三行保持不变,因为两个值均已填充。
您需要此正则表达式来替换数据
q'[(Dept_ID: from '.*' to '';|Dept_ID: from '' to '.*';)]'
请注意,中间的条表示OR。左侧与to
值为NULL的部门匹配,左侧与from
值为NULL的部门匹配。
将匹配的字符串替换为NULL字符串。
要限制更新记录的范围,必须定义越野车记录的确切逻辑。在此示例中,我希望两个记录必须具有相同的e_id
并在t_id
上排序
使用LEAD
和LAG
,您将检查以下内容和前面的内容,以检查更改为空和从空更改为的情况已满。
请注意,我正在使用LIKE
来过滤行以获得更好的性能。
查询更新前的最终检查:)
with al as (
select T_ID, E_ID, DETAIL_LOG,
lead(DETAIL_LOG) over (partition by e_id order by t_id) DETAIL_LOG_LEAD,
lag(DETAIL_LOG) over (partition by e_id order by t_id) DETAIL_LOG_LAG
from AUDIT_TABLE)
select T_ID, E_ID,
/* updated entry */
regexp_replace(detail_log, q'[(Dept_ID: from '.*' to '';|Dept_ID: from '' to '.*';)]', '') DETAIL_LOG
from al
where (DETAIL_LOG like q'[%Dept_ID: from '_%' to '';%]' and /* first wrong record */
DETAIL_LOG_LEAD like q'[%Dept_ID: from '' to '_%';%]') OR
(DETAIL_LOG like q'[%Dept_ID: from '' to '_%';%]' and /* second wrong record */
DETAIL_LOG_LAG like q'[%Dept_ID: from '_%' to '';%]')
;
返回
T_ID E_ID DETAIL_LOG
---------- ---------- ------------
1 111 USER_1; Salary: from '25' to '30';
2 111 USER_1;
更新
UPDATE
语句是使用IN
(子查询)限制范围的上述查询的简单重构。
update AUDIT_TABLE
set DETAIL_LOG = regexp_replace(detail_log, q'[(Dept_ID: from '.*' to '';|Dept_ID: from '' to '.*';)]', '')
where (T_ID, E_ID) in
-- query from above that limits the updated rows
在此清理后删除空审计记录是一个简单的步骤。
答案 1 :(得分:0)
如果您要保留的所有行的数据都为Salary:
,且与您的情况相同,则末尾有相邻的冒号,则可以考虑删除没有Salary:
的行;
delete audit_table where instr(detail_log,'Salary:') = 0;
,然后通过修剪detail_log
字符串后的其余部分来更新Dept_ID:
列的数据
update audit_table
set detail_log = regexp_replace(detail_log, '(.*)Dept_ID:.*', '\1');