如何将一个表中的值插入另一个表,然后更新原始表?

Posted

技术标签:

【中文标题】如何将一个表中的值插入另一个表,然后更新原始表?【英文标题】:How to insert values from one table into another and then update the original table? 【发布时间】:2017-05-03 10:54:35 【问题描述】:

使用Oracle,有没有办法将一个表中的值插入到另一个表中,然后从插入的表中获取一个标识值并更新原始列中的一列?

TABLE_1 为空

ID    VALUE
-----------

TABLE_2 中的值 ...

ID    VALUE
-----------
0     Val 1
0     Val 2
0     Val 3

...插入到 TABLE_1(带有标识列)

ID    VALUE
-----------
1     Val 1
2     Val 2
3     Val 3

然后用 ID 更新 TABLE_2

ID    VALUE
-----------
1     Val 1
2     Val 2
3     Val 3

【问题讨论】:

【参考方案1】:

您需要获得此类要求的程序。该解决方案使用 SELECT ... FOR UPDATE 锁定源表,以防止另一个会话获取我们想要提供新 ID 的记录。它还为我们提供了 WHERE CURRENT OF 语法,可以轻松识别我们需要更新的记录。

此解决方案假设存在用于填充标识列的序列。我们还有其他可用的选项(包括 12C 中的自动增量),但 RETURNING 子句是获取新值的关键。

declare
    cursor c2 is
        select * from table2
        for update of id;
    r2 c2%rowtype;
    new_id t1.id%type;
begin
    open c2;
    loop
        fetch c2 in r2;
        exit when c2%notfound;
        /* new record */
        insert into t1
        values (t1_seq.nextval, t2.value)
        returning t1.id into new_id;
        /* update existing record with id*/
        update t2
        set id = new_id
        where current of c2;
    end loop;
    commit;
end;
/

此解决方案是 Row-By-Row”,这是确保新 T1.ID 应用于 T2 中正确行的最简单方法。如果 T1 很小和/或这是一个 on -off 练习,这可能很好。但如果性能是一个问题,可以进行调整。

【讨论】:

谢谢,光标是我要走的路,我想知道我是否可以避免它,或者我是否可以做一个花哨的 MERGE。 另外,非常感谢for update。我在游标中不知道这一点,我猜如果没有它,我会卡住一段时间。 我确实有疑问,触发器会是更好的方法吗?即在主表上一个触发器在第二个表中插入值,然后在第二个表上使用另一个触发器来更新主表中的值,如果我错了,请纠正我。 @user75ponic - 触发器可以用于在table_1 中插入新记录,但对现有记录没有帮助。所以这似乎是一个新问题。【参考方案2】:

如果表 2 中有很多行,我建议您使用 bulk collect。 它将帮助您提高数据库的性能。像这样:

declare 
type type_table2 is table of table2%rowtype index by binary_integer;
vt_table2 type_table2;
cursor cur_table2 is select * from table2;
begin
open cur_table2;
  loop
  fetch cur_table2 bulk collect into vt_table2 limit 500;
    for i in 1..vt_table2.count loop
      begin
        insert into table1
        values(i, vt.table2(i).value);
        update table2
        set id = i
        where current of cur_table2; 
      exception when other then
      excp := SQLERRM;
      dbms_output.put_line('Error:'||excp);
      end;
    end loop;
  exit when cur_table%notfound;
  end loop;
close cur_table2;
commit;
exception when other then
  excp := SQLERRM;
  dbms_output.put_line('Error:'||excp);
end;

【讨论】:

谢谢。我将运行这两种类型,看看是否有任何性能改进。如果您不介意我问,这里的批量收集是做什么的? > BULK COLLECT:SELECT 语句通过一次提取检索多行,提高数据检索速度 您需要一个数组来保存内容并在本地搜索。 fetch cur_table2 bulk collect into vt_table2 limit 500; 所以基本上,一次获取游标的所有记录,然后循环遍历? > 具体来说,集合的内存存储在程序全局区 (PGA),而不是系统全局区 (SGA)。 SGA 内存由连接到 Oracle 数据库的所有会话共享,但为每个会话分配 PGA 内存。因此,如果一个程序需要 5MB 的内存来填充一个集合并且有 100 个同时连接,那么除了分配给 SGA 的内存之外,该程序还会消耗 500MB 的 PGA 内存 [链接] (oracle.com/technetwork/issue-archive/2008/08-mar/…)跨度> @JonathanPeel 是的,以 500 条为单位获取所有记录,然后根据您的程序分析数据。

以上是关于如何将一个表中的值插入另一个表,然后更新原始表?的主要内容,如果未能解决你的问题,请参考以下文章

根据另一个表中的值插入和/或更新记录

如何将一个表中的值插入到另一个表中?

如何从1个表中选择许多行并将其插入另一个表中特定行的特定JSONB字段中?但是在单个原始SQL查询中

需求: 将一个表中的数据插入另一个表, 然后根据条件对表中数据进行更新

雪花我们如何遍历临时表的每一行并将其值插入到另一个表中,其中每个字段的值都是单行?

在另一个表中插入一行时如何自动增加一个表中的值