20

我有一个序列用于在 oracle 表中播种我的(基于整数的)主键。

似乎此序列并不总是用于将新值插入表中。如何使序列与表中的实际值同步?

4

7 回答 7

19

如果 ID 是您的 PK 列的名称,而 PK_SEQ 是您的序列的名称:

  1. 通过 SELECT MAX(ID) FROM tableName 查找最高 PK 的值

  2. 通过 SELECT PK_SEQ.NEXTVAL FROM DUAL 查找下一个 PK_SEQ 的值

  3. 如果 #2 > #1 则无需执行任何操作,假设您将这些值视为真正的代理键
  4. 否则,通过 ALTER SEQUENCE PK_SEQ INCREMENT BY [#1 value - #2 value] 更改序列以跳转到最大 ID
  5. 通过 SELECT PK_SEQ.NEXTVAL FROM DUAL 增加序列

  6. 通过 ALTER SEQUENCE PK_SEQ INCREMENT BY 1 将序列增量值重置为 1

这一切都假设您在执行此操作时没有新的插入到表中......

于 2009-09-15T12:01:55.567 回答
11

简而言之,游戏吧:

-- Current sequence value is 1000

ALTER SEQUENCE x INCREMENT BY -999;
Sequence altered.

SELECT X.NEXTVAL FROM DUAL;
1

ALTER SEQUENCE x INCREMENT BY 1;
Sequence altered.

您可以获得表中使用的最大序列值,进行数学运算并相应地更新序列。

于 2009-09-15T11:44:37.223 回答
8
Declare
  difference INTEGER;
  sqlstmt varchar2(255);
  sequenceValue Number;
begin
sqlstmt := 'ALTER SEQUENCE YOURSEQUENCE INCREMENT BY ';
select YOURSEQUENCE.NEXTVAL into sequenceValue from dual;
select  (nvl(Max(YOURID),0) - sequenceValue)+1 into difference from YOURTABLE;
if difference > 0 then
  EXECUTE IMMEDIATE sqlstmt || difference;
  select  YOURSEQUENCE.NEXTVAL INTO sequenceValue from dual;
  EXECUTE IMMEDIATE sqlstmt || 1;
end if;
end;
于 2013-04-10T15:03:01.057 回答
5

我制作了这个脚本,因为我没有在网上找到一个可以将我的所有序列动态设置为当前最高 ID 的脚本。在 Oracle 11.2.0.4 上测试。

DECLARE
  difference         INTEGER;
  sqlstmt            VARCHAR2(255) ;
  sqlstmt2           VARCHAR2(255) ;
  sqlstmt3           VARCHAR2(255) ;
  sequenceValue      NUMBER;
  sequencename       VARCHAR2(30) ;
  sequencelastnumber INTEGER;
  CURSOR allseq
  IS
     SELECT sequence_name, last_number FROM user_sequences ORDER BY sequence_name;
BEGIN
  DBMS_OUTPUT.enable(32000) ;
  OPEN allseq;
  LOOP
    FETCH allseq INTO sequencename, sequencelastnumber;
    EXIT
  WHEN allseq%NOTFOUND;
    sqlstmt  := 'ALTER SEQUENCE ' || sequencename || ' INCREMENT BY ';
    --Assuming: <tablename>_id is <sequencename>
    sqlstmt2 := 'select (nvl(Max(ID),0) - :1)+1 from ' || SUBSTR(sequencename, 1, LENGTH(sequencename) - 3) ;
    --DBMS_OUTPUT.PUT_LINE(sqlstmt2);
    --Attention: makes use of user_sequences.last_number --> possible cache problems!
    EXECUTE IMMEDIATE sqlstmt2 INTO difference USING sequencelastnumber;
    IF difference > 0 THEN
      DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt || difference) ;
      EXECUTE IMMEDIATE sqlstmt || difference;
      sqlstmt3 := 'SELECT ' || sequencename ||'.NEXTVAL from dual';
      DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt3 || ' INTO sequenceValue') ;
      EXECUTE IMMEDIATE sqlstmt3 INTO sequenceValue;
      DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt || 1) ;
      EXECUTE IMMEDIATE sqlstmt || 1;
      DBMS_OUTPUT.PUT_LINE('') ;
    END IF;
  END LOOP;
  CLOSE allseq;
END;
于 2014-05-26T00:38:38.783 回答
1

在某些情况下,您可能会发现简单地获取当前最大值然后

drop sequence x;
create sequence x start with {current max + 1};

完成放置后,该应用程序将被破坏。但这将阻止任何人在此期间插入行,并且创建序列很快。确保您在序列上重新创建任何授权,因为当序列被删除时,这些授权将被删除。您可能希望手动重新编译任何依赖于序列的 plsql。

于 2009-09-15T13:15:11.023 回答
0

加起来https://stackoverflow.com/a/15929548/1737973,但不采取SEQUENCENAME.NEXTVAL因此不会导致一个位置超过它应该是:

DECLARE
  difference INTEGER;
  alter_sequence_statement VARCHAR2 (255);
  sequence_value NUMBER;
BEGIN
  --   Base for the statement that will set the sequence value.
  alter_sequence_statement :=
      'ALTER SEQUENCE SEQUENCENAME INCREMENT BY ';

  --   Fetch current last sequence value used.
  SELECT
    --   You could maybe want to make some further computations just
    -- below if the sequence is using caching.
    last_number
  INTO sequence_value
  FROM all_sequences
  WHERE sequence_owner = 'SEQUENCEOWNER' AND sequence_name = 'SEQUENCENAME';

  --   Compute the difference.
  SELECT max(id) - sequence_value + 1 INTO difference
  FROM SCHEMANAME.TABLENAME;

  IF difference <> 0 THEN
    --   Set the increment to a big offset that puts the sequence near
    -- its proper value.
    EXECUTE IMMEDIATE alter_sequence_statement || difference;

    --   This 'sequence_value' will be ignored, on purpose.
    SELECT SEQUENCENAME.NEXTVAL INTO sequence_value FROM dual;

    --   Resume the normal pace of incrementing one by one.
    EXECUTE IMMEDIATE alter_sequence_statement || 1;
  END IF;
END;

免责声明:如果序列使用缓存(all_sequences.cache_size设置为大于 0),您可能希望在计算差异步骤中考虑它。

Oracle 文档all sequences...

于 2017-08-07T08:03:01.830 回答
0
  • 从表中选择最大值并为其设置序列值。

SELECT setval('table_id_seq_name', (SELECT MAX(id) FROM table_name));

于 2020-11-26T09:34:43.270 回答