0

在 Oracle 中,我需要将记录从源插入到目标,然后在更新目标后更新源的 PROCESSED_DATE 字段。

一种方法是使用游标和逐行循环来实现相同的目的。

有没有其他方法可以有效地做同样的事情?

4

4 回答 4

1

不需要光标。假设您要传输那些尚未传输的行(由 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;  

更多详细信息请参见手册:

于 2012-08-29T17:04:50.500 回答
0

触发器应该起作用。目标表可以有一个触发器,在更新时,用处理日期更新源表的列。

于 2012-08-29T17:15:14.670 回答
0

从别人那里得到另一个答案。认为该解决方案似乎比启用隔离级别更合理,因为我所有的新记录都将 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;

/

让我知道对此有任何进一步的想法。非常感谢您在这方面的所有帮助。

于 2012-08-30T15:57:23.467 回答
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;

上面的代码只是一个示例,并对表的结构做了一些假设。

它首先查询源表,并且只会插入和更新这些记录——这意味着您无需担心其他会话在运行时同时将更多记录插入源表。

它也可以很容易地更改为批量处理行(使用 fetch LIMIT 子句和循环),而不是像我在这里那样一次性处理。

于 2012-08-30T02:42:44.987 回答