在 Oracle 中,我需要将记录从源插入到目标,然后在更新目标后更新源的 PROCESSED_DATE 字段。
一种方法是使用游标和逐行循环来实现相同的目的。
有没有其他方法可以有效地做同样的事情?
在 Oracle 中,我需要将记录从源插入到目标,然后在更新目标后更新源的 PROCESSED_DATE 字段。
一种方法是使用游标和逐行循环来实现相同的目的。
有没有其他方法可以有效地做同样的事情?
不需要光标。假设您要传输那些尚未传输的行(由 processes_date 中的 NULL 值标识)。
insert into target_table (col1, col2, col3)
select col1, col2, col3
from source_table
where processed_date is null;
update source_table
set processed_date = current_timestamp
where processed_date is null;
commit;
为避免更新在 INSERT 运行时或在 INSERT 和更新之间插入的行,请以可序列化模式启动事务。
在运行 INSERT 之前,使用以下语句启动事务:
set transaction isolation level SERIALIZABLE;
更多详细信息请参见手册:
触发器应该起作用。目标表可以有一个触发器,在更新时,用处理日期更新源表的列。
从别人那里得到另一个答案。认为该解决方案似乎比启用隔离级别更合理,因为我所有的新记录都将 PROCESSED_DATE 设为空(在目标表中插入记录时插入的 30 行)此外 PROCESSED_DATE = NULL 行只能通过以下方式更新使用我的工作。没有其他用户可以随时更新这些记录。
declare
date_stamp date;
begin
select sysdate
into date_stamp
from dual;
update source set processed_date = date_stamp
where procedded_date is null;
Insert into target
select * from source
where processed_date = date_stamp;
commit;
end;
/
让我知道对此有任何进一步的想法。非常感谢您在这方面的所有帮助。
在这种情况下,我首选的解决方案是使用 PL/SQL 数组和批处理 DML,例如:
DECLARE
CURSOR c IS SELECT * FROM tSource;
TYPE tarrt IS TABLE OF c%ROWTYPE INDEX BY BINARY_INTEGER;
tarr tarrt;
BEGIN
OPEN c;
FETCH c BULK COLLECT INTO tarr;
CLOSE c;
FORALL i IN 1..tarr.COUNT
INSERT INTO tTarget VALUES tarr(i);
FORALL i IN 1..tarr.COUNT
UPDATE tSource SET processed_date = SYSDATE
WHERE tSource.id = tarr(i).id;
END;
上面的代码只是一个示例,并对表的结构做了一些假设。
它首先查询源表,并且只会插入和更新这些记录——这意味着您无需担心其他会话在运行时同时将更多记录插入源表。
它也可以很容易地更改为批量处理行(使用 fetch LIMIT 子句和循环),而不是像我在这里那样一次性处理。