获取序列的最小值
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_sequences
或 dba_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的,但是.
我在数据库中定义了大约 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_sequences
或 dba_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的,但是