Oracle 12c - 复杂的更新和删除
Oracle 12c - complicated update and delete
我在审计中有以下场景 table (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
”值(在另一个 table) 中。有数百万条这样的记录需要清理。捕获了多个字段更改的记录,即 item_id 01
需要更新以清除 Dept_ID
: 审计消息,只有 Dept_ID
审计记录的记录需要删除(item_id 02
).可能有其他对在两个记录中都只有 Dept ID
审计消息,在这种情况下都需要删除。触发逻辑已得到修复,因此当 Dept ID
中没有实际更改时不会再创建错误记录,但是需要清理在错误期间已经创建的记录。可能有些行只有一对记录,在这种情况下,这些记录不需要 updated/deleted,因为 Dept_ID 实际上已更改为 null 或从 null 更改为值。
因此在修复上述数据集后应该存在以下内容:
t_id e_id detail_log date_created
01 111 USER_1; Salary: from '25' to '30'; 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
我已经准备好执行此操作的删除和更新语句,但是如果我删除了一对记录中的一个,则更新将找不到另一条记录,因为它依赖于已删除的记录来找到它,反之亦然更新声明。我想使用 merge 语句但不确定如何使用。有什么想法吗?
如果那些应该保留的所有行都有一个 Salary:
的数据,最后有相邻的冒号,就像你的情况一样,然后考虑删除没有 Salary:
;
的行
delete audit_table where instr(detail_log,'Salary:') = 0;
然后通过修剪 Dept_ID:
字符串
之后的其余部分来更新 detail_log
列的数据
update audit_table
set detail_log = regexp_replace(detail_log, '(.*)Dept_ID:.*', '');
所以假设这样的测试数据
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
您检查以下和前面的记录以检查 的条件是否更改为 emtpy 和 从空 的变化是满的。
请注意,我正在使用 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 '';%]')
;
returns
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
在此清理后删除空 审核记录是一个微不足道的步骤。
我在审计中有以下场景 table (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
”值(在另一个 table) 中。有数百万条这样的记录需要清理。捕获了多个字段更改的记录,即 item_id 01
需要更新以清除 Dept_ID
: 审计消息,只有 Dept_ID
审计记录的记录需要删除(item_id 02
).可能有其他对在两个记录中都只有 Dept ID
审计消息,在这种情况下都需要删除。触发逻辑已得到修复,因此当 Dept ID
中没有实际更改时不会再创建错误记录,但是需要清理在错误期间已经创建的记录。可能有些行只有一对记录,在这种情况下,这些记录不需要 updated/deleted,因为 Dept_ID 实际上已更改为 null 或从 null 更改为值。
因此在修复上述数据集后应该存在以下内容:
t_id e_id detail_log date_created
01 111 USER_1; Salary: from '25' to '30'; 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
我已经准备好执行此操作的删除和更新语句,但是如果我删除了一对记录中的一个,则更新将找不到另一条记录,因为它依赖于已删除的记录来找到它,反之亦然更新声明。我想使用 merge 语句但不确定如何使用。有什么想法吗?
如果那些应该保留的所有行都有一个 Salary:
的数据,最后有相邻的冒号,就像你的情况一样,然后考虑删除没有 Salary:
;
delete audit_table where instr(detail_log,'Salary:') = 0;
然后通过修剪 Dept_ID:
字符串
detail_log
列的数据
update audit_table
set detail_log = regexp_replace(detail_log, '(.*)Dept_ID:.*', '');
所以假设这样的测试数据
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
您检查以下和前面的记录以检查 的条件是否更改为 emtpy 和 从空 的变化是满的。
请注意,我正在使用 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 '';%]')
;
returns
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
在此清理后删除空 审核记录是一个微不足道的步骤。