在Oracle中,我有一个要求,我需要在Source中将记录插入Target,然后在目标更新后更新源的PROCESSED_DATE字段。
1种方法是使用游标并逐行循环来实现相同的目的。
还有其他方法以有效的方式做同样的事情吗?
答案 0 :(得分:1)
不需要游标。假设您要传输那些尚未传输的行(由processed_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;
有关详细信息,请参阅手册:
答案 1 :(得分:0)
触发器应该有效。目标表可以有一个触发器,在更新时,使用处理日期更新源表的列。
答案 2 :(得分:0)
我在这种情况下的首选解决方案是使用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;
以上代码仅作为示例,并对表的结构做出一些假设。
它首先查询源表,并且只会插入和更新这些记录 - 这意味着您无需担心其他会话在运行时同时在源表中插入更多记录。
也可以轻松更改为批量处理行(使用提取LIMIT子句和循环),而不是像我这里一样一次性处理。
答案 3 :(得分:0)
从其他人那里得到另一个答案。认为解决方案似乎比启用隔离级别更合理,因为我的所有新记录都将PROCESSED_DATE设置为null(在记录插入Target表时插入了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;
/
让我知道对此的任何进一步想法。非常感谢您对此的所有帮助。