Sql Oracle-与插入、更新和删除合并的过程
我需要创建一个程序,以尽可能有效的方式处理这个案例,因为数据量非常大 我有一个名为ORDER_a的表,它每天都会收到一个完整的负载,并且所有的记录都会被再次插入。 我有一个名为ORDER_B的表,它是ORDER_a的副本,包含相同的数据和一些额外的控制日期。 我还有一个表管理器来保存开始和完成日期,以及过程是否正在运行 在所有插入都按顺序A完成之后,我想执行一个过程,对于顺序A上的每个记录,必须查找具有相同标识符主键的记录:表B中的顺序id 如果存在具有相同order_id的记录,并且任何其他列都已更改,则必须对表B执行更新 如果存在具有相同order_id且没有值的记录在已修改的其他列中,不应执行任何操作,表B中的记录必须保持不变。 如果没有具有相同订单id的记录,则必须将其插入表B中。 如果订单_B上有一条记录在订单_a上不再存在,并且该记录已被删除,则列标志_deleted必须更新为1。 我的桌子是这样的Sql Oracle-与插入、更新和删除合并的过程,sql,oracle,stored-procedures,oracle19c,Sql,Oracle,Stored Procedures,Oracle19c,我需要创建一个程序,以尽可能有效的方式处理这个案例,因为数据量非常大 我有一个名为ORDER_a的表,它每天都会收到一个完整的负载,并且所有的记录都会被再次插入。 我有一个名为ORDER_B的表,它是ORDER_a的副本,包含相同的数据和一些额外的控制日期。 我还有一个表管理器来保存开始和完成日期,以及过程是否正在运行 在所有插入都按顺序A完成之后,我想执行一个过程,对于顺序A上的每个记录,必须查找具有相同标识符主键的记录:表B中的顺序id 如果存在具有相同order_id的记录,并且任何其他列
CREATE TABLE ORDER_A
(
ORDER_ID NUMBER NOT NULL,
ORDER_CODE VARCHAR2(50),
ORDER_STATUS VARCHAR2(20),
ORDER_USER_ID NUMBER,
ORDER_DATE TIMESTAMP(6),
CHECKSUM_CODE VARCHAR2(40),
PRIMARY KEY (ORDER_ID)
);
CREATE TABLE ORDER_B
(
ORDER_ID NUMBER NOT NULL,
ORDER_CODE VARCHAR2(50),
ORDER_STATUS VARCHAR2(20),
ORDER_USER_ID NUMBER,
ORDER_DATE TIMESTAMP(6)
INSERT_AT TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
UPDATED_AT TIMESTAMP(6),
CHECKSUM_CODE VARCHAR2(40),
FLAG_DELETED NUMBER(1),
PRIMARY KEY (ORDER_ID)
);
-- index on checksum column for both tables
CREATE INDEX idx_cksum on ORDER_A (CHECKSUM_CODE ASC);
CREATE INDEX idx_cksum on ORDER_B (CHECKSUM_CODE ASC);
-- Manager table
CREATE TABLE MANAGER
(
TABLE_NAME VARCHAR2(40),
PROCEDURE_NAME VARCHAR2(50),
START_TS TIMESTAMP(6),
FINISH_TS TIMESTAMP(6),
IS_RUNNING NUMBER(1)
);
我在考虑下面的过程,但我不确定这是否是最好的方法以及如何处理删除案例
create or replace procedure MERGE_DATA_ORDER
DECLARE
is_running number;
ex_running EXCEPTION;
BEGIN
SELECT IS_RUNNING INTO is_running FROM MANAGER WHERE PROCEDURE_NAME = 'MERGE_DATA_ORDER';
IF is_running = 1
then RAISE ex_running
ELSE
-- Update the flag on manager table
UPDATE MANAGER SET IS_RUNNING = 1, START_TS = SYSTIMESTAMP WHERE PROCEDURE_NAME = 'MERGE_DATA_ORDER';
COMMIT;
-- update all records with a checksum using STANDARD_HASH with MD5
UPDATE ORDER_A
SET CHECKSUM_CODE =
STANDARD_HASH
(
ORDER_ID ||
ORDER_CODE ||
ORDER_STATUS ||
ORDER_USER_ID ||
ORDER_DATE,
'MD5'
);
COMMIT;
-- then, I do a MERGE operation, using the checksum as a comparator
merge into ORDER_B b
using (select a.* from ORDER_A a) m
on (m.ORDER_ID = b.ORDER_ID)
when matched then
update
set
b.ORDER_ID = m.ORDER_ID,
b.ORDER_CODE = m.ORDER_CODE,
b.ORDER_STATUS = m.ORDER_STATUS,
b.ORDER_USER_ID = m.ORDER_USER_ID,
b.ORDER_DATE = m.ORDER_DATE,
b.COD_CHECKSUM = m.COD_CHECKSUM,
b.DAT_UPDATE = SYSTIMESTAMP
where b.CHECKSUM_CODE <> m.CHECKSUM_CODE
when not matched then
insert (
b.ORDER_ID,
b.ORDER_CODE,
b.ORDER_STATUS,
b.ORDER_USER_ID,
b.ORDER_DATE,
b.COD_CHECKSUM
)
values (
m.ORDER_ID,
m.ORDER_CODE,
m.ORDER_STATUS,
m.ORDER_USER_ID,
m.ORDER_DATE,
m.COD_CHECKSUM
);
END IF;
-- set the flag to 0
UPDATE MANAGER SET IS_RUNNING = 0, FINISH_TS = SYSTIMESTAMP WHERE PROCEDURE_NAME = 'MERGE_DATA_ORDER';
COMMIT;
END;
/
我需要一些帮助来完成这段代码,性能提示和处理删除问题 我认为您可以将此作为一条语句作为数据加载的一部分来完成。假设订单A已经加载,但我稍后会对此进行评论。然后,您可以通过在ORDER_a和ORDER_B之间进行完全外部联接,以及使用用例语句从ORDER_a或ORDER_B投影正确的值来定义插入/更新的结果。类似地,您可以投影DELTED标志。它看起来像这样。在本例中,我跳过了MD5,但如果真的需要,可以添加它-稍后也会详细介绍
select
case
when ( b.order_id is null ) then a.order_id
else case when (
b.ORDER_ID != m.ORDER_ID or
b.ORDER_CODE != m.ORDER_CODE or
b.ORDER_STATUS != m.ORDER_STATUS or
b.ORDER_USER_ID != m.ORDER_USER_ID or
b.ORDER_DATE != m.ORDER_DATE or
b.DAT_UPDATE != SYSTIMESTAMP ) then b.order_id else a.order_id end
end as newOrder_id
, case when ( b.order_id is null ) then a.order_code
else case when (
b.ORDER_ID != m.ORDER_ID or
b.ORDER_CODE != m.ORDER_CODE or
b.ORDER_STATUS != m.ORDER_STATUS or
b.ORDER_USER_ID != m.ORDER_USER_ID or
b.ORDER_DATE != m.ORDER_DATE or
b.DAT_UPDATE != SYSTIMESTAMP ) then b.order_code else a.order_code end
end as newOrder_code
, case when ( b.order_id is null ) then a.order_status
else case when (
b.ORDER_ID != m.ORDER_ID or
b.ORDER_CODE != m.ORDER_CODE or
b.ORDER_STATUS != m.ORDER_STATUS or
b.ORDER_USER_ID != m.ORDER_USER_ID or
b.ORDER_DATE != m.ORDER_DATE or
b.DAT_UPDATE != SYSTIMESTAMP ) then b.order_status else a.order_status end
end as newOrder_status
/* etc... ( Repeat for all projected columns )
Then for the flag_deleted column */
, case when ( a.order_id is null ) then 1
when ( b.order_id is null ) then 0
else b.flag_deleted
end as newFlag_deleted
from Order_b b
full outer join Order_a a
on b.order_id = a.order_id
ORDER_A可能是一个外部表,所以您只需要在它前面加上
CREATE TABLE NEW_ORDER_A as select....
然后你就有了你需要的结果
在您的示例中,您的性能下降的地方是ORDER_a的更新。您正在生成redo、undo并失去任何压缩优势。您也在维护索引,但不需要索引。
假设您有资源,您现在可以使用直接路径和并行,这将可以很好地扩展
最后,如果您真的需要MD5,则需要在每列之间添加一个特殊字符,否则is将不明确。例如,以下文件具有相同的MD5
COL1 COL2
AA BBB
AAB BB
删除将需要一个单独的命令;没有办法使合并的一部分。类似于从订单b中删除,其中订单id不在订单a中选择订单id;此外,插入时,请确保将校验和代码从订单A带到订单B。