将Oracle序列重置为现有列中下一个值的最佳方法?

Cad*_*oux 44 sql oracle primary-key sequence oracle10g

出于某种原因,过去的人不使用sequence.NEXTVAL插入数据.因此,当我使用sequence.NEXTVAL来填充表时,我得到了PK违规,因为该数字已在表中使用.

如何更新下一个值以使其可用?现在,我只是一遍又一遍地插入,直到它成功(INSERT INTO tbl (pk) VALUES (sequence.NEXTVAL)),然后同步下一个.

Bas*_*Roy 84

您可以临时增加缓存大小并执行一次虚拟选择,然后将缓存大小重置为1.例如

ALTER SEQUENCE mysequence INCREMENT BY 100;

select mysequence.nextval from dual;

ALTER SEQUENCE mysequence INCREMENT BY 1;
Run Code Online (Sandbox Code Playgroud)

  • 偷偷摸摸的.我喜欢. (6认同)
  • 如果您只是想将起始值重置为数字,请查看Leniel Macaferi的答案。更改顺序<seq>重新启动,以<num>开始; (3认同)
  • 你的意思是增加“增量”。缓存大小完全是另一回事:/sf/answers/3890320661/ (3认同)
  • 您可能要确保在更改序列时没有其他人正在使用该序列。 (2认同)

Cad*_*oux 16

这两个过程让我重置序列并根据表中的数据重置序列(对此客户端使用的编码约定道歉):

CREATE OR REPLACE PROCEDURE SET_SEQ_TO(p_name IN VARCHAR2, p_val IN NUMBER)
AS
   l_num   NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;

   -- Added check for 0 to avoid "ORA-04002: INCREMENT must be a non-zero integer"
   IF (p_val - l_num - 1) != 0
   THEN
      EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by ' || (p_val - l_num - 1) || ' minvalue 0';
   END IF;

   EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;

   EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by 1 ';

   DBMS_OUTPUT.put_line('Sequence ' || p_name || ' is now at ' || p_val);
END;

CREATE OR REPLACE PROCEDURE SET_SEQ_TO_DATA(seq_name IN VARCHAR2, table_name IN VARCHAR2, col_name IN VARCHAR2)
AS
   nextnum   NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'SELECT MAX(' || col_name || ') + 1 AS n FROM ' || table_name INTO nextnum;

   SET_SEQ_TO(seq_name, nextnum);
END;
Run Code Online (Sandbox Code Playgroud)


DCo*_*kie 13

如果您可以指望表处于稳定状态且没有新插入的时间段,则应该这样做(未经测试):

DECLARE
  last_used  NUMBER;
  curr_seq   NUMBER;
BEGIN
  SELECT MAX(pk_val) INTO last_used FROM your_table;

  LOOP
    SELECT your_seq.NEXTVAL INTO curr_seq FROM dual;
    IF curr_seq >= last_used THEN EXIT;
    END IF;
  END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)

这使您可以使序列与表同步,而不会删除/重新创建/重新授予序列.它也不使用DDL,因此不执行隐式提交.当然,你将不得不追捕那些坚持不使用序列来填充列的人...

  • 这行得通,只需要在IF行后加上一个“ END IF” (2认同)

Len*_*rri 10

在我来说,我有一个叫做序列PS_LOG_SEQ其中有一个LAST_NUMBER = 3920.

然后我将一些数据从PROD我的本地机器导入并插入到PS_LOG表中.生产数据有多个20000行,最新的LOG_ID(主键)是20070.导入后我尝试在此表中插入新行但是在保存时我遇到了类似这样的异常:

ORA-00001: unique constraint (LOG.PS_LOG_PK) violated
Run Code Online (Sandbox Code Playgroud)

当然这PS_LOG_SEQPS_LOG表格相关的序列有关.的LAST_NUMBER是与I导入的数据,其已经从使用的下一个ID值的碰撞PS_LOG_SEQ.

为了解决这个问题,我使用此命令将序列更新为最新的\ max(LOG_ID)+ 1:

alter sequence PS_LOG_SEQ restart start with 20071;
Run Code Online (Sandbox Code Playgroud)

此命令重置该LAST_NUMBER值,然后我可以在表中插入新行.不再碰撞了.:)

注意:alter sequence命令是Oracle 12c中的新增功能.

  • 在 Oracle 19c 中仍然有效 (3认同)
  • 您链接的文档说“要以不同的编号重新启动序列,您必须删除并重新创建它。”,没有提及 RESTART 选项。链接版本错误? (2认同)

tec*_*ech 9

使用oracle 10.2g:

select  level, sequence.NEXTVAL
from  dual 
connect by level <= (select max(pk) from tbl);
Run Code Online (Sandbox Code Playgroud)

将当前序列值设置为表格的最大值(pk)(即下次调用NEXTVAL将为您提供正确的结果); 如果您使用Toad,请按F5键运行语句,而不是F9,它会对输出进行分页(从而停止增量,通常为500行).好的一面:这个解决方案只有DML,而不是DDL.只有SQL而且没有PL-SQL.不好的一面:这个解决方案输出max(pk)行输出,即通常比ALTER SEQUENCE解决方案慢.

  • 这将始终根据您在表中拥有的行数来增加序列。如果序列不是 0,它将过冲。 (2认同)