Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用insert select复制记录,然后更新同一组记录中的属性_Sql_Database_Oracle_Plsql - Fatal编程技术网

Sql 使用insert select复制记录,然后更新同一组记录中的属性

Sql 使用insert select复制记录,然后更新同一组记录中的属性,sql,database,oracle,plsql,Sql,Database,Oracle,Plsql,我有一个Oracle过程,我想在其中执行以下操作: 将记录从一个表复制到另一个表 更新原始记录以表明它们已被复制 目前,我使用FOR循环分别处理每条记录。这是可行的,但要做一些我认为可能更简单的事情需要很多代码 我想: 消除for循环,并通过插入将记录复制到。。。选择陈述 如果复制成功,则更新所有选定记录。 这看起来很简单,只需一个INSERT和一个UPDATE语句,其中包含相同的WHERE子句。但是,在执行这两条语句之间,可能会插入更多需要复制的记录。如果我使用相同的WHERE子句,我可能会将

我有一个Oracle过程,我想在其中执行以下操作:

将记录从一个表复制到另一个表 更新原始记录以表明它们已被复制 目前,我使用FOR循环分别处理每条记录。这是可行的,但要做一些我认为可能更简单的事情需要很多代码

我想:

消除for循环,并通过插入将记录复制到。。。选择陈述 如果复制成功,则更新所有选定记录。 这看起来很简单,只需一个INSERT和一个UPDATE语句,其中包含相同的WHERE子句。但是,在执行这两条语句之间,可能会插入更多需要复制的记录。如果我使用相同的WHERE子句,我可能会将尚未实际处理的记录标记为已处理


是否有一种方法可以保存主键列表,以便在两个语句中使用或合并语句?或者你会建议我坚持使用FOR循环,一次处理一条记录吗?欢迎所有构造性输入。

如果在事务中运行这两条语句,任何失败都将导致insert和update回滚

insert into tgt..
select * from src
where <condition>
  and row_status <> 'copied'; --ignoring records after they have been copied once?

update src
set row_status = 'copied'
where <same_where_condition_as_before>

commit;

如果在读取源表后插入了新行,则可能需要再次运行该块,并在适当的情况下更改where条件。

如果源表有很小的机会同时更新,Rajesh的回答应该可以很好地执行。如果源表经常更新,可序列化事务将经常失败

另一种方法是使用flashback查询来查看表中的时间点。as-of语法是查看表在最近的历史中的外观的一种方便方法

declare
    v_current_scn number;
begin
    v_current_scn := dbms_flashback.get_system_change_number;

    insert into tgt..
    select * from src
    where <condition>
        and row_status <> 'copied'; --ignoring records after they have been copied once?

    update src
    set row_status = 'copied'
    where rowid in
        (
            select rowid
            from src as of scn v_current_scn
            where <same_where_condition_as_before>
        );
end;
/

最好使用insert into..select语句,然后更新原始表中复制的记录。从隔离级别设置为可重复读取的事务开始工作?事务应该可以轻松处理此问题。For循环太过分了。@SylvainLeroux谢谢你提供的信息。看起来事务级隔离可以满足我的需要。您会推荐这种方法而不是使用set transaction read only吗?这取决于源表更新的频率。如果不常见,则接受Rajesh的答案,将其放入循环中,并在ORA-08177失败时重新运行它:无法序列化此事务的访问。如果它经常更新,那么我会使用闪回。另一种方法是使用返回语法,但这需要更多的代码来保存IDs.Jon-对于Oracle的读取一致性模型,OP的问题不需要序列化。如果我认为OP需要序列化当前事务,我会选择select for update。你怎么认为?