Oracle 12c - 复杂的更新和删除

Posted

技术标签:

【中文标题】Oracle 12c - 复杂的更新和删除【英文标题】:Oracle 12c - complicated update and delete 【发布时间】:2019-01-13 03:44:31 【问题描述】:

我在审计表 (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”值(在另一个表中)没有变化时,批处理过程中存在一个错误,该错误会触发插入此审计表并创建这些记录“Dept_ID: from .. to”。有数百万条这样的记录需要清理。捕获了多个字段更改的记录,即item_id 01,需要更新以清除Dept_ID:审计消息,并且需要删除只有Dept_ID审计记录的记录(item_id 02)。可能有其他对在两条记录中都只有Dept ID 审计消息,在这种情况下,都需要删除。触发逻辑已修复,因此当Dept ID 中没有实际更改时不会创建更多错误记录,但是需要清理在错误期间已经创建的记录。可能存在一对只有一条记录的行,在这种情况下,不需要更新/删除这些记录,因为 Dept_ID 实际上已更改为空值或从空值更改为值。

所以在修复上述数据集后应该存在以下内容:

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

我已经准备好删除和更新语句来执行此操作,但如果我删除这对记录中的一条记录,则更新将找不到另一条记录,因为它依赖于已删除的记录来找到它,反之亦然更新语句.我想使用合并语句,但不知道如何。有什么想法吗?

【问题讨论】:

【参考方案1】:

所以假设这样的测试数据

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 上排序

使用 LEADLAG 检查以下和前面的记录,以检查 change to emtpychange from empty 的条件是否已满足。

请注意,我使用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

在此清理之后删除 审计记录是一个简单的步骤。

【讨论】:

如果在部门 ID 实际更改为 NULL 或从 NULL 更改为 NOT NULL 时我没有有效记录,这将起作用。我不想触及那些不受此错误影响的记录,那些没有一对的记录,从非空变为空,然后紧接着另一条记录从空变为非空。 那么您将不得不以某种方式更仔细地解释您如何配对要删除的记录。例如。两条记录必须具有相同的e_id,并在t_id 上排序。如果没有这些信息,只有 IF(即推测性)答案是可能的...... t_id 在pair中是连续的,e_id是相同的,但是同一个e_id可能还有其他审计记录。 好吧检查更新的答案,现在应该是确切的解决方案。 向你致敬。【参考方案2】:

如果应该保留的所有行都具有 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:.*', '\1');

Rextester Demo

【讨论】:

@user3224907 请分享那些添加到已经给出的两行的案例,以便我们理解您的意思。 现在请看我的描述。也添加了数据。

以上是关于Oracle 12c - 复杂的更新和删除的主要内容,如果未能解决你的问题,请参考以下文章

如何安装Oracle 12c数据库软件

如何安装Oracle 12c数据库软件

Oracle 12c 用相同的数据更新多行

Data Guard:Oracle 12c –新增和更新的功能 (Doc ID 1558256.1)

如何在 oracle 12c 中使用多个数据更新单个列

oracle 12C版本的下载安装