获取序列的最小值

Getting min value of the sequence

我在数据库中定义了大约 100 个序列,在执行测试后将其设置为某个数字。

例如: 有一个序列:suppier_seq。 那将从 1 开始,现在它的 currval 是 101.

我需要根据最小值重置所有存在的序列。

如果我提取序列的 DDL,它会以当前值开头:

CREATE SEQUENCE  "RMS14"."SUPPLIER_SEQUENCE"  MINVALUE 0 MAXVALUE 99999999999 INCREMENT BY 1 START WITH 101 CACHE 100 NOORDER  NOCYCLE ;

我需要用最小值重新启动序列。

如何通过SQL获取序列的最小值?

您无法判断序列的原始 START WITH 值是什么。您只能将它基于 MINVALUE,或者使用它(即使它为零),或者向它加一,或者仅在它不为零时才这样做。

您可以从 user_sequences 视图获取您自己的序列的当前值,并使用 PL/SQL 块循环遍历它们,并在途中生成 drop 和 create 语句:

set serveroutput on
begin
  for r in (
    select 'DROP SEQUENCE "' || sequence_name || '"' as drop_stmt,
      'CREATE SEQUENCE "' || sequence_name || '"'
        || ' MINVALUE ' || min_value
        || ' MAXVALUE ' || max_value
        || ' INCREMENT BY ' || increment_by
        || ' START WITH ' || min_value
        || case when cache_size = 0 then ' NOCACHE' else ' CACHE ' || cache_size end
        || case when order_flag = 'Y' then ' ORDER' else ' NOORDER' end
        || case when cycle_flag = 'Y' then ' CYCLE' else ' NOCYCLE' end
        as create_stmt
    from user_sequences
  )
  loop
    dbms_output.put_line(r.drop_stmt);
--    execute immediate r.drop_stmt;
    dbms_output.put_line(r.create_stmt);
--    execute immediate r.create_stmt;
  end loop;
end;
/

我已将 execute immediate 语句注释掉,以避免在没有任何检查的情况下被复制和粘贴而导致的事故;最初它只会显示它会运行的命令,例如

PL/SQL procedure successfully completed.

DROP SEQUENCE "SUPPLIER_SEQUENCE"
CREATE SEQUENCE "SUPPLIER_SEQUENCE" MINVALUE 0 MAXVALUE 99999999999 INCREMENT BY 1 START WITH 0 CACHE 100 NOORDER NOCYCLE
...

如果您在另一个模式中工作并且拥有正确的权限,您可以查询 all_sequencesdba_sequences,并指定所有者:

    select 'DROP SEQUENCE "' || sequence_owner || '"."' || sequence_name ||'"' as drop_stmt,
      'CREATE SEQUENCE "' || sequence_owner || '"."' || sequence_name || '"'
        || ' MINVALUE ' || min_value
...

另一种方法是改变顺序,将INCREMENT BY设置为当前最高值(或最高值减去MINVALUE),调用 nextval,然后重置增量。这在动态上有点混乱,尤其是因为当它像这样直接在循环中完成时,你需要第二级动态语句来获取当前序列值,但基本上是相同的想法:

declare
  l_nextval number;
begin
  for r in (
    select 'BEGIN EXECUTE IMMEDIATE ''ALTER SEQUENCE "' || sequence_name || '"'
        || ' INCREMENT BY -''|| ("' || sequence_name || '".nextval - ' || min_value ||'); END;'
        as alter_stmt_1,
      'SELECT "' || sequence_name || '".nextval from dual' as adjust_stmt,
      'ALTER SEQUENCE "' || sequence_name || '"'
        || ' INCREMENT BY ' || increment_by
        as alter_stmt_2
    from user_sequences
  )
  loop
    dbms_output.put_line(r.alter_stmt_1);
--    execute immediate r.alter_stmt_1;
    dbms_output.put_line(r.adjust_stmt);
--    execute immediate r.adjust_stmt into l_nextval;
    dbms_output.put_line(r.alter_stmt_2);
--    execute immediate r.alter_stmt_2;
  end loop;
end;
/

PL/SQL procedure successfully completed.

BEGIN EXECUTE IMMEDIATE 'ALTER SEQUENCE "SUPPLIER_SEQUENCE" INCREMENT BY -'|| ("SUPPLIER_SEQUENCE".nextval - 0); END;
SELECT "SUPPLIER_SEQUENCE".nextval from dual
ALTER SEQUENCE "SUPPLIER_SEQUENCE" INCREMENT BY 1

您还可以在循环内生成动态语句,这对于这种方法来说可能更简洁:

declare
  l_alter_stmt_1 varchar2(4000);
  l_alter_stmt_2 varchar2(4000);
  l_adjust_stmt varchar2(4000);
  l_nextval number;
begin
  for r in (select * from user_sequences) loop
    l_adjust_stmt := 'select "' || r.sequence_name || '".nextval from dual';
    execute immediate l_adjust_stmt into l_nextval;
    l_alter_stmt_1 := 'ALTER SEQUENCE "' || r.sequence_name || '"'
        || ' INCREMENT BY '|| (r.min_value - l_nextval);
    l_alter_stmt_2 := 'ALTER SEQUENCE "' || r.sequence_name || '"'
        || ' INCREMENT BY ' || r.increment_by;
    dbms_output.put_line(l_alter_stmt_1);
--    execute immediate r.alter_stmt_1;
    dbms_output.put_line(l_adjust_stmt);
--    execute immediate l_adjust_stmt into l_nextval;
    dbms_output.put_line(l_alter_stmt_2);
--    execute immediate l_alter_stmt_2;
  end loop;
end;
/

PL/SQL procedure successfully completed.

ALTER SEQUENCE "SUPPLIER_SEQUENCE" INCREMENT BY -101
select "SUPPLIER_SEQUENCE".nextval from dual
ALTER SEQUENCE "SUPPLIER_SEQUENCE" INCREMENT BY 1

问题具体是关于11g的,但是.