在PostgreSQL中,我可以执行以下操作:

ALTER SEQUENCE serial RESTART WITH 0;


是否有Oracle等效项?

评论

在这里查看“序列重置”。

警告:以下所有代码仅对最初使用“ increment by 1”创建的序列有效。如果原始序列是用增量!= 1创建的;应用上述任何步骤之后,增量将变为1!可以从user_sequences视图中获取要使用的正确增量值。

删除并重新创建序列

#1 楼

这是一个从Oracle专家Tom Kyte将任何序列重置为0的好方法。在下面的链接中也对正反两面进行了很好的讨论。

tkyte@TKYTE901.US.ORACLE.COM> 
create or replace
procedure reset_seq( p_seq_name in varchar2 )
is
    l_val number;
begin
    execute immediate
    'select ' || p_seq_name || '.nextval from dual' INTO l_val;

    execute immediate
    'alter sequence ' || p_seq_name || ' increment by -' || l_val || 
                                                          ' minvalue 0';

    execute immediate
    'select ' || p_seq_name || '.nextval from dual' INTO l_val;

    execute immediate
    'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
end;
/


从此页面:动态SQL重设序列值:如何重置序列?

评论


@Dougman:嗨,我是初学者。...在上面的答案中,为什么您在最后提到in子句,而不是立即执行'select'|| p_seq_name || '.nextval INTO l_val from dual';;

– Thiyagu ATR
13年2月23日在8:48

@Thiyagu:在PL / SQL中,这是使用立即执行捕获最多返回1行的选择输出的语法。这是有关立即执行的文档:docs.oracle.com/cd/B28359_01/appdev.111/b28370/…

–道格·波特(Doug Porter)
13年2月26日在21:05

@matra我看不到一种场景,在该场景中,需要重置一个序列并处于并发环境中,而其他用户也需要使用同一序列。

– Ekevoo
2014-09-19 14:26

为什么需要选择序列,为什么不选择最后一行'alter sequence'|| p_seq_name || '增加1个小数值0';

–悟空
18/12/15在12:17

#2 楼

不能真正重启AFAIK。 (如果我错了,请纠正我!)。

但是,如果要将其设置为0,则可以将其删除并重新创建。

如果需要要将其设置为特定值,可以将INCREMENT设置为负值并获得下一个值。

,即,如果序列为500,则可以通过
ALTER SEQUENCE serial INCREMENT BY -400;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;


评论


只是对PLSQL中的人员的注释。确保添加“限制1;”或“ rownum = 1”到select语句,否则您可能最终运行nextVal几次,并增加-400多次。

–user830914
2014年6月6日21:58



错误序列.NEXTVAL低于MINVALUE,当INCREMENT BY-<< big_number >>时无法实例化

– zloctb
2015年8月17日在20:42



#3 楼

这是我的方法:


删除序列
重新创建它

示例:

--Drop sequence

DROP SEQUENCE MY_SEQ;

-- Create sequence 

create sequence MY_SEQ
minvalue 1
maxvalue 999999999999999999999
start with 1
increment by 1
cache 20;


评论


请注意,删除操作将使依赖于该序列的所有对象失效,因此必须重新编译它们。

–道格·波特(Doug Porter)
2011-12-23 18:57

您还必须重新授予从序列中选择的所有授予。

– GreenGiant
2013年1月7日23:37

#4 楼

alter sequence serial restart start with 1;

此功能已在18c中正式添加,但自12.1起正式提供。
在12.1中使用此未记录的功能无疑是安全的。即使该语法未包含在官方文档中,也由Oracle软件包DBMS_METADATA_DIFF生成。我已经在生产系统上使用过几次。但是,我创建了一个Oracle Service请求,他们验证了它不是文档错误,该功能确实不受支持。
在18c中,该功能未出现在SQL语言语法中,但包含在《数据库管理员指南》中。

评论


嘿@Jon,我知道这个未记录的功能,但是,我不知道它是从DBMS_METADATA_DIFF生成的脚本中看到的。您能否让我知道您是如何生成脚本,哪个过程等的?我也会尝试进行测试。

– Lalit Kumar B
15年5月8日在9:38

@LalitKumarB我在回答此问题时偶然发现了该功能。

–乔恩·海勒(Jon Heller)
15年5月8日在13:23

啊,明白了。谢谢 :-)

– Lalit Kumar B
15年5月8日在14:24

如果序列的最小值大于0,请考虑写入...重新启动时应从0 MINVALUE 0开始

–conceptdeluxe
19年4月28日在11:26

信息:此功能也可用于Oracle DB 12.2(12c)。好的答案,谢谢!

–t0r0X
8月12日13:25

#5 楼

我的方法是对Dougman的示例进行小小的扩展。

扩展是...

将种子值作为参数传递。为什么?我喜欢称之为将序列重置为某些表中使用的最大ID的事物。我最终从另一个脚本调用了此proc,该脚本对整个序列序列执行了多次调用,将nextval重置回某个足够高的水平,以至于不会在我将序列值用作唯一标识符的情况下引起主键冲突。

它也尊重以前的最小值。实际上,如果所需的p_val或现有的最小值小于当前值或计算出的下一个值,它实际上可能会将下一个值推得更高。然后等到最后看到包装程序“修复所有序列”时就可以使用。它调用它并使用序列命名约定以编程方式指定所有内容,并查找现有表/字段中使用的最大值...

create or replace
procedure Reset_Sequence( p_seq_name in varchar2, p_val in number default 0)
is
  l_current number := 0;
  l_difference number := 0;
  l_minvalue user_sequences.min_value%type := 0;

begin

  select min_value
  into l_minvalue
  from user_sequences
  where sequence_name = p_seq_name;

  execute immediate
  'select ' || p_seq_name || '.nextval from dual' INTO l_current;

  if p_Val < l_minvalue then
    l_difference := l_minvalue - l_current;
  else
    l_difference := p_Val - l_current;
  end if;

  if l_difference = 0 then
    return;
  end if;

  execute immediate
    'alter sequence ' || p_seq_name || ' increment by ' || l_difference || 
       ' minvalue ' || l_minvalue;

  execute immediate
    'select ' || p_seq_name || '.nextval from dual' INTO l_difference;

  execute immediate
    'alter sequence ' || p_seq_name || ' increment by 1 minvalue ' || l_minvalue;
end Reset_Sequence;


现在我们在做饭加气!

上面的过程将检查表中字段的最大值,从表/字段对中构建序列名称,并使用感应到的最大值调用“ Reset_Sequence”。

接下来是这个难题的最后一块,还有锦上添花的东西...

create or replace
procedure Reset_Sequence_to_Data(
  p_TableName varchar2,
  p_FieldName varchar2
)
is
  l_MaxUsed NUMBER;
BEGIN

  execute immediate
    'select coalesce(max(' || p_FieldName || '),0) from '|| p_TableName into l_MaxUsed;

  Reset_Sequence( p_TableName || '_' || p_Fieldname || '_SEQ', l_MaxUsed );

END Reset_Sequence_to_Data;


在我的实际数据库中,大约有一百个其他序列通过该复位机制,因此在上述过程中还有97个对Reset_Sequence_to_Data的调用。

喜欢吗?讨厌它?无动于衷?

评论


我喜欢它。我将添加一个变量,以获取并保存user_sequences表中的值增量。 (可能不是1)。注意:可能需要改用all_sequences表。在这种情况下,您可能还需要传递sequence_owner。

– Harv
2011年7月22日15:16



无法给您足够的支持。在处理数据迁移时,这是一个非常普遍的问题,如果您对序列感到困惑,这是AFAIK的最佳方法。

– Dominique Eav
2012年11月27日16:59

赞成,因为这是一种极好的方法。唯一的缺点是,它可能导致RAC系统中无法预测的行为,其中l_current可能是各种值之一,具体取决于运行脚本的节点。重新运行脚本可能会导致不同的结果。我发现如果我多次运行它,最终会确定为特定值。

–杰弗里·肯普(Jeffrey Kemp)
14年8月19日在3:46

#6 楼

以下脚本将序列设置为所需值:

给出一个新创建的名为PCS_PROJ_KEY_SEQ的序列和表PCS_PROJ:

BEGIN
   DECLARE
      PROJ_KEY_MAX       NUMBER := 0;
      PROJ_KEY_CURRVAL   NUMBER := 0;
   BEGIN

    SELECT MAX (PROJ_KEY) INTO PROJ_KEY_MAX FROM PCS_PROJ;
    EXECUTE IMMEDIATE 'ALTER SEQUENCE PCS_PROJ_KEY_SEQ INCREMENT BY ' || PROJ_KEY_MAX;
    SELECT PCS_PROJ_KEY_SEQ.NEXTVAL INTO PROJ_KEY_CURRVAL FROM DUAL;
    EXECUTE IMMEDIATE 'ALTER SEQUENCE PCS_PROJ_KEY_SEQ INCREMENT BY 1';

END;
END;
/


评论


您在第一个DDL语句中忘记了减号(此外,还有一个额外的END关键字)。

– Priidu Neemre
16/12/15在14:23



#7 楼

此存储过程重新启动了我的序列:

Create or Replace Procedure Reset_Sequence  
  is
  SeqNbr Number;
begin
   /*  Reset Sequence 'seqXRef_RowID' to 0    */
   Execute Immediate 'Select seqXRef.nextval from dual ' Into SeqNbr;
   Execute Immediate 'Alter sequence  seqXRef increment by - ' || TO_CHAR(SeqNbr) ;
   Execute Immediate 'Select seqXRef.nextval from dual ' Into SeqNbr;
   Execute Immediate 'Alter sequence  seqXRef increment by 1';
END;


/

评论


+1-您也可以将其参数化以传递序列名称。

– DCookie
2013年2月6日4:49



#8 楼

在Oracle中还有另一种重置序列的方法:设置maxvaluecycle属性。当序列的nextval命中maxvalue时,如果设置了cycle属性,则它将再次从序列的minvalue开始。

与设置负increment by相比,此方法的优势在于序列可以在重置过程运行时继续使用,从而减少了需要采取某种形式的中断来进行重置的机会。

maxvalue的值必须大于当前的nextval,因此下面的过程包括一个可选参数,允许在程序中选择nextval和设置cycle属性之间再次访问该序列的情况下使用缓冲区。仍然允许另一个会话获取值0的可能性,这对您来说可能不是问题。如果是这样,您始终可以:


在第一个alter中设置minvalue 1
排除第二个nextval fetch
移动语句以将nocycle属性设置为另一个过程,以便以后运行(假设您要这样做)。


#9 楼

Jezus,所有这些仅用于索引重新启动的编程...
我可能是个白痴,但是对于Oracle 12之前的版本(具有重新启动功能),simpel出了什么问题:

drop sequence blah;
create sequence blah 




评论


删除序列的主要问题是,它失去了对其授予的特权。

–乔恩·海勒(Jon Heller)
17年4月26日在13:27

好的,乔恩。通常,还原这些文件所花费的时间将比所有编程花费的时间少得多。优秀的DBA通常具有脚本,因此不应该成为问题:-)

–劳伦斯
17年6月23日在14:55

#10 楼

1)假设您创建了一个SEQUENCE,如下所示:

CREATE SEQUENCE TESTSEQ
INCREMENT BY 1
MINVALUE 1
MAXVALUE 500
NOCACHE
NOCYCLE
NOORDER


2)现在,您从SEQUENCE中获取值。可以说我已经获取了四次,如下所示。

SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual


3)在执行了上述四个命令之后,SEQUENCE的值将为4。现在假设我已经重置了SEQUENCE的值再次设为1。请遵循以下步骤。按照如下所示的顺序执行所有步骤:


ALTER SEQUENCE TESTSEQ INCREMENT BY -3;
SELECT TESTSEQ.NEXTVAL FROM dual
ALTER SEQUENCE TESTSEQ INCREMENT BY 1;
SELECT TESTSEQ.NEXTVAL FROM dual


#11 楼

更改序列的INCREMENT值,将其递增,然后再将其更改回是很轻松的,此外,您还具有不必像删除/重新创建序列那样重新建立所有授予的好处。

#12 楼

您可以使用CYCLE选项,如下所示:

CREATE SEQUENCE test_seq
MINVALUE 0
MAXVALUE 100
START WITH 0
INCREMENT BY 1
CYCLE;


在这种情况下,当序列达到MAXVALUE(100)时,它将循环使用MINVALUE(0)。

如果序列递减,则该序列将回收到MAXVALUE。

评论


对于下降投票者(永远不会看到此评论):CYCLE属性正是我用来完成序列重置的属性。重置是自动的事实并不意味着它没有达到目标-OP并未指定重置必须针对预先存在的序列!

–Jeromy法语
18年7月3日在22:17

#13 楼

我创建了一个块来重置所有序列:

DECLARE
    I_val number;
BEGIN
    FOR US IN
        (SELECT US.SEQUENCE_NAME FROM USER_SEQUENCES US)
    LOOP
        execute immediate 'select ' || US.SEQUENCE_NAME || '.nextval from dual' INTO l_val;
        execute immediate 'alter sequence ' || US.SEQUENCE_NAME || ' increment by -' || l_val || ' minvalue 0';
        execute immediate 'select ' || US.SEQUENCE_NAME || '.nextval from dual' INTO l_val;
        execute immediate 'alter sequence ' || US.SEQUENCE_NAME || ' increment by 1 minvalue 0';
    END LOOP;
END;


#14 楼

这是一个更健壮的过程,用于更改序列返回的下一个值,以及更多操作。


首先,由于没有使用传入的字符串,因此它可以防止SQL注入攻击。要直接创建任何动态SQL语句,
其次,它防止将下一个序列值设置在最小或最大序列值的范围之外。 next_value将为!= min_value,并且介于min_valuemax_value之间。
清理时会考虑当前(或建议的)increment_by设置以及所有其他顺序设置。
除第四个参数外第一个是可选的,除非指定,否则将当前序列设置作为默认值。如果未指定任何可选参数,则不执行任何操作。
最后,如果您尝试更改不存在的序列(或当前用户不拥有的序列),则会引发ORA-01403: no data found错误。

代码如下:

CREATE OR REPLACE PROCEDURE alter_sequence(
    seq_name      user_sequences.sequence_name%TYPE
  , next_value    user_sequences.last_number%TYPE := null
  , increment_by  user_sequences.increment_by%TYPE := null
  , min_value     user_sequences.min_value%TYPE := null
  , max_value     user_sequences.max_value%TYPE := null
  , cycle_flag    user_sequences.cycle_flag%TYPE := null
  , cache_size    user_sequences.cache_size%TYPE := null
  , order_flag    user_sequences.order_flag%TYPE := null)
  AUTHID CURRENT_USER
AS
  l_seq user_sequences%rowtype;
  l_old_cache user_sequences.cache_size%TYPE;
  l_next user_sequences.min_value%TYPE;
BEGIN
  -- Get current sequence settings as defaults
  SELECT * INTO l_seq FROM user_sequences WHERE sequence_name = seq_name;

  -- Update target settings
  l_old_cache := l_seq.cache_size;
  l_seq.increment_by := nvl(increment_by, l_seq.increment_by);
  l_seq.min_value    := nvl(min_value, l_seq.min_value);
  l_seq.max_value    := nvl(max_value, l_seq.max_value);
  l_seq.cycle_flag   := nvl(cycle_flag, l_seq.cycle_flag);
  l_seq.cache_size   := nvl(cache_size, l_seq.cache_size);
  l_seq.order_flag   := nvl(order_flag, l_seq.order_flag);

  IF next_value is NOT NULL THEN
    -- Determine next value without exceeding limits
    l_next := LEAST(GREATEST(next_value, l_seq.min_value+1),l_seq.max_value);

    -- Grab the actual latest seq number
    EXECUTE IMMEDIATE
        'ALTER SEQUENCE '||l_seq.sequence_name
            || ' INCREMENT BY 1'
            || ' MINVALUE '||least(l_seq.min_value,l_seq.last_number-l_old_cache)
            || ' MAXVALUE '||greatest(l_seq.max_value,l_seq.last_number)
            || ' NOCACHE'
            || ' ORDER';
    EXECUTE IMMEDIATE 
      'SELECT '||l_seq.sequence_name||'.NEXTVAL FROM DUAL'
    INTO l_seq.last_number;

    l_next := l_next-l_seq.last_number-1;

    -- Reset the sequence number
    IF l_next <> 0 THEN
      EXECUTE IMMEDIATE 
        'ALTER SEQUENCE '||l_seq.sequence_name
            || ' INCREMENT BY '||l_next
            || ' MINVALUE '||least(l_seq.min_value,l_seq.last_number)
            || ' MAXVALUE '||greatest(l_seq.max_value,l_seq.last_number)
            || ' NOCACHE'
            || ' ORDER';
      EXECUTE IMMEDIATE 
        'SELECT '||l_seq.sequence_name||'.NEXTVAL FROM DUAL'
      INTO l_next;
    END IF;
  END IF;

  -- Prepare Sequence for next use.
  IF COALESCE( cycle_flag
             , next_value
             , increment_by
             , min_value
             , max_value
             , cache_size
             , order_flag) IS NOT NULL
  THEN
    EXECUTE IMMEDIATE 
      'ALTER SEQUENCE '||l_seq.sequence_name
          || ' INCREMENT BY '||l_seq.increment_by
          || ' MINVALUE '||l_seq.min_value
          || ' MAXVALUE '||l_seq.max_value
          || CASE l_seq.cycle_flag
             WHEN 'Y' THEN ' CYCLE' ELSE ' NOCYCLE' END
          || CASE l_seq.cache_size
             WHEN 0 THEN ' NOCACHE'
             ELSE ' CACHE '||l_seq.cache_size END
          || CASE l_seq.order_flag
             WHEN 'Y' THEN ' ORDER' ELSE ' NOORDER' END;
  END IF;
END;


#15 楼

在我的项目中,一旦发生有人不使用序列而手动输入记录的情况,因此我必须手动重置序列值,为此,我在下面的sql代码段中编写了以下代码:

declare
max_db_value number(10,0);
cur_seq_value number(10,0);
counter number(10,0);
difference number(10,0);
dummy_number number(10);

begin

-- enter table name here
select max(id) into max_db_value from persons;
-- enter sequence name here
select last_number into cur_seq_value from user_sequences where  sequence_name = 'SEQ_PERSONS';

difference  := max_db_value - cur_seq_value;

 for counter in 1..difference
 loop
    -- change sequence name here as well
    select SEQ_PERSONS.nextval into dummy_number from dual;
 end loop;
end;


请注意,如果顺序滞后,上述代码将适用。

#16 楼

以下是使所有自动递增序列与实际数据匹配的方法:



创建一个过程以强制执行下一个值,如该线程中所述: />
CREATE OR REPLACE PROCEDURE Reset_Sequence(
    P_Seq_Name IN VARCHAR2,
    P_Val      IN NUMBER DEFAULT 0)
IS
  L_Current    NUMBER                      := 0;
  L_Difference NUMBER                      := 0;
  L_Minvalue User_Sequences.Min_Value%Type := 0;
BEGIN
  SELECT Min_Value
  INTO L_Minvalue
  FROM User_Sequences
  WHERE Sequence_Name = P_Seq_Name;
  EXECUTE Immediate 'select ' || P_Seq_Name || '.nextval from dual' INTO L_Current;
  IF P_Val        < L_Minvalue THEN
    L_Difference := L_Minvalue - L_Current;
  ELSE
    L_Difference := P_Val - L_Current;
  END IF;
  IF L_Difference = 0 THEN
    RETURN;
  END IF;
  EXECUTE Immediate 'alter sequence ' || P_Seq_Name || ' increment by ' || L_Difference || ' minvalue ' || L_Minvalue;
  EXECUTE Immediate 'select ' || P_Seq_Name || '.nextval from dual' INTO L_Difference;
  EXECUTE Immediate 'alter sequence ' || P_Seq_Name || ' increment by 1 minvalue ' || L_Minvalue;
END Reset_Sequence;



创建另一个过程以使所有序列与实际内容一致:

CREATE OR REPLACE PROCEDURE RESET_USER_SEQUENCES_TO_DATA
IS
  STMT CLOB;
BEGIN
  SELECT 'select ''BEGIN'' || chr(10) || x || chr(10) || ''END;'' FROM (select listagg(x, chr(10)) within group (order by null) x FROM ('
    || X
    || '))'
  INTO STMT
  FROM
    (SELECT LISTAGG(X, ' union ') WITHIN GROUP (
    ORDER BY NULL) X
    FROM
      (SELECT CHR(10)
        || 'select ''Reset_Sequence('''''
        || SEQ_NAME
        || ''''','' || coalesce(max('
        || COL_NAME
        || '), 0) || '');'' x from '
        || TABLE_NAME X
      FROM
        (SELECT TABLE_NAME,
          REGEXP_SUBSTR(WTEXT, 'NEW\.(\S*) IS NULL',1,1,'i',1) COL_NAME,
          REGEXP_SUBSTR(BTEXT, '(\.|\s)([a-z_]*)\.nextval',1,1,'i',2) SEQ_NAME
        FROM USER_TRIGGERS
        LEFT JOIN
          (SELECT NAME BNAME,
            TEXT BTEXT
          FROM USER_SOURCE
          WHERE TYPE = 'TRIGGER'
          AND UPPER(TEXT) LIKE '%NEXTVAL%'
          )
        ON BNAME = TRIGGER_NAME
        LEFT JOIN
          (SELECT NAME WNAME,
            TEXT WTEXT
          FROM USER_SOURCE
          WHERE TYPE = 'TRIGGER'
          AND UPPER(TEXT) LIKE '%IS NULL%'
          )
        ON WNAME             = TRIGGER_NAME
        WHERE TRIGGER_TYPE   = 'BEFORE EACH ROW'
        AND TRIGGERING_EVENT = 'INSERT'
        )
      )
    ) ;
  EXECUTE IMMEDIATE STMT INTO STMT;
  --dbms_output.put_line(stmt);
  EXECUTE IMMEDIATE STMT;
END RESET_USER_SEQUENCES_TO_DATA;



注释:


过程从触发器代码中提取名称,并且不依赖命名约定
要在执行前检查生成的代码,请在最后两行切换注释


#17 楼

我的另一种选择是用户不需要知道值,系统便可以获取并使用变量进行更新。

--Atualizando sequence da tabela SIGA_TRANSACAO, pois está desatualizada
DECLARE
 actual_sequence_number INTEGER;
 max_number_from_table INTEGER;
 difference INTEGER;
BEGIN
 SELECT [nome_da_sequence].nextval INTO actual_sequence_number FROM DUAL;
 SELECT MAX([nome_da_coluna]) INTO max_number_from_table FROM [nome_da_tabela];
 SELECT (max_number_from_table-actual_sequence_number) INTO difference FROM DUAL;
IF difference > 0 then
 EXECUTE IMMEDIATE CONCAT('alter sequence [nome_da_sequence] increment by ', difference);
 --aqui ele puxa o próximo valor usando o incremento necessário
 SELECT [nome_da_sequence].nextval INTO actual_sequence_number from dual;
--aqui volta o incremento para 1, para que futuras inserções funcionem normalmente
 EXECUTE IMMEDIATE 'ALTER SEQUENCE [nome_da_sequence] INCREMENT by 1';
 DBMS_OUTPUT.put_line ('A sequence [nome_da_sequence] foi atualizada.');
ELSE
 DBMS_OUTPUT.put_line ('A sequence [nome_da_sequence] NÃO foi atualizada, já estava OK!');
END IF;
END;


#18 楼

对我有用的存储过程

create or replace
procedure reset_sequence( p_seq_name in varchar2, tablename in varchar2 )
is
    l_val number;
    maxvalueid number;
begin
    execute immediate 'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    execute immediate 'select max(id) from ' || tablename INTO maxvalueid;
    execute immediate 'alter sequence ' || p_seq_name || ' increment by -' || l_val || ' minvalue 0';
    execute immediate 'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    execute immediate 'alter sequence ' || p_seq_name || ' increment by '|| maxvalueid ||' minvalue 0';  
    execute immediate 'select ' || p_seq_name || '.nextval from dual' INTO l_val;
    execute immediate 'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
end;


如何使用存储过程:

execute reset_sequence('company_sequence','company');