【问题标题】:Inserting Row Number based on existing value in the table根据表中的现有值插入行号
【发布时间】:2021-08-30 02:13:20
【问题描述】:

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

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

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

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

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

有什么想法可以实现吗?

【问题讨论】:

  • 你为什么有这个要求,标准的自动增量列和时间戳列会有什么问题?
  • 为什么不能只使用序列?您提到有多个进程插入,但这正是序列优化的目的。
  • 我不能使用序列,因为所有其他处理都已经使用游标将数据插入到此表中。重写大量代码不是我想做的事情,我也无权更改现有代码。而且我也无法更改现有的表结构。
  • 恐怕没有免费的午餐。 +1 sequence 选项。
  • 使用游标的其他进程的意义是什么 - 是那些找到当前最大值然后在执行单行插入的循环内递增;你也可以这样做,但你想(正确地)这样一个insert...select?如果是这样,您仍然可以在语句中设置值,但这并不理想。你现在如何避免冲突?无论如何...如果您无法阻止其他进程尝试手动设置row_nbr,您仍然可以拥有一个忽略它们使用的数字并用序列值覆盖它的触发器。

标签: oracle plsql plsqldeveloper


【解决方案1】:

听起来其他进程正在寻找当前最大 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;

或通过查询表作为查询的一部分,这不需要 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 使用序列,这将是一个自动增量列,但您说您不能更改表结构;并且您需要让其他进程在不修改的情况下继续工作。您仍然可以使用序列和触发器的方法来做到这一点,让触发器始终从序列中设置 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 * 即使在那个构造中,并且明确列出临时表列);并且任何提供 row_nbr 的现有插入不需要修改,它们提供的值将被序列覆盖。

db<>fiddle 显示插入和未指定 row_nbr

【讨论】:

    猜你喜欢
    • 2018-10-17
    • 2013-12-03
    • 2013-05-08
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 2015-02-06
    • 1970-01-01
    相关资源
    最近更新 更多