如何将一个表中的值插入另一个表,然后更新原始表?
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查询中
需求: 将一个表中的数据插入另一个表, 然后根据条件对表中数据进行更新