根据 table 中的现有值插入行号

Inserting Row Number based on existing value in the table

我有一个要求,我需要根据 table 中已经存在的值在 table 中插入行号。比如当前table中最大row_nbr条记录是这样的:

+----------+----------+------------+---------+
| FST_NAME | LST_NAME | STATE_CODE | ROW_NBR |
+----------+----------+------------+---------+
| John     | Doe      |         13 |     123 |
+----------+----------+------------+---------+

现在,我需要使用给定的 FST_NAME 和 LST_NAME 值插入更多记录。 ROW_NBR 需要在将数据插入 table 时生成,值从 123 自动递增。

我不能使用序列,因为我的加载进程不是唯一将数据插入此 table 的进程。而且我也不能使用游标,因为由于数据量很大,TEMP space 很快就会被填满。我正在插入如下所示的数据:

insert into final_table
( fst_name,lst_name,state_code)
(select * from staging_table
where state_code=13);

有什么实现方法吗?

听起来其他进程正在寻找当前的最大值 row_nbr 并在游标循环中进行单行插入时递增它。

可以做一些功能相似的事情,要么提前找到最大值并递增它(如果你已经运行这个在PL/SQL块):

insert into final_table (fst_name, lst_name, state_code, row_nbr)
select st.*, variable_holding_maximum + rownum
from staging_table st
where st.state_code=13;

或者通过查询 table 作为查询的一部分,不需要 PL/SQL:

insert into final_table (fst_name, lst_name, state_code, row_nbr)
select st.*, (select max(row_nbr) from final_table) + rownum
from staging_table st
where st.state_code=13;

db<>fiddle

但这不是一个好的解决方案,因为它不能防止尝试同时插入的不同进程和会话发生冲突;但是游标循环方法也不会,除非它正在捕获唯一约束错误并重新尝试使用新值。

It would be better 使用序列,这将是一个自增列但是你说你不能改变 table 结构;并且您需要让其他进程继续工作而无需修改。您仍然可以使用序列和触发器方法来做到这一点,让触发器始终设置序列中的 row_nbr 值,而不管插入语句是否提供了值。

如果您创建一个从当前最大值开始的序列,类似于:

create sequence final_seq start with <current max + 1>

或不手动查找:

declare
  start_with pls_integer;
begin
  select nvl(max(row_nbr), 0) + 1 into start_with from final_table;
  execute immediate 'create sequence final_seq start with ' || start_with;
end;
/

那么你的触发器可能只是:

create trigger final_trig
before insert on final_table
for each row
begin
  :new.row_nbr := final_seq.nextval;
end;
/

那么你的 insert ... select 语句不需要提供甚至不需要考虑 row_nbr 值,所以你可以保持现在的状态(除了我会避免 select * 甚至在该构造中,并明确列出暂存 table 列);并且任何提供 row_nbr 的现有插入都不需要修改,它们提供的值只会从序列中被覆盖。

db<>fiddle 显示指定和不指定 row_nbr 的插入内容。