문제

~ 안에 포스트그레SQL, 다음과 같이 할 수 있습니다.

ALTER SEQUENCE serial RESTART WITH 0;

Oracle과 동등한 것이 있습니까?

도움이 되었습니까?

해결책

Oracle 전문가로부터 시퀀스를 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
또 다른 좋은 토론도 여기에 있습니다. 시퀀스를 재설정하는 방법은 무엇입니까?

다른 팁

진정한 재시작은 불가능합니다 AFAIK.(틀렸다면 정정해주세요!)

하지만 0으로 설정하고 싶다면 삭제하고 다시 생성하면 됩니다.

특정 값으로 설정하려면 INCREMENT를 음수 값으로 설정하고 다음 값을 얻을 수 있습니다.

즉, 시퀀스가 ​​500인 경우 다음을 통해 100으로 설정할 수 있습니다.

ALTER SEQUENCE serial INCREMENT BY -400;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;

이것이 내 접근 방식입니다.

  1. 시퀀스를 삭제하세요
  2. 다시 만들어 보세요

예:

--Drop sequence

DROP SEQUENCE MY_SEQ;

-- Create sequence 

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

내 접근 방식은 더그먼의 예.

확장 프로그램은...

시드 값을 매개변수로 전달합니다.왜?나는 시퀀스를 재설정하는 것을 다시 호출하고 싶습니다. 일부 테이블에서 사용되는 최대 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;

해당 프로시저는 그 자체로 유용하지만 이제 이 프로시저를 호출하고 시퀀스 명명 규칙을 사용하여 프로그래밍 방식으로 모든 것을 지정하고 기존 테이블/필드에서 사용되는 최대값을 찾는 또 다른 프로시저를 추가해 보겠습니다.

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;

이제 가스로 요리를 해보자!

위의 절차는 테이블에서 필드의 최대 값을 확인하고 테이블/필드 쌍에서 시퀀스 이름을 구축하고 호출합니다. "재설정_시퀀스" 감지된 최대 값으로.

이 퍼즐의 마지막 조각과 금상첨화는 다음에 나옵니다...

create or replace
procedure Reset_All_Sequences
is
BEGIN

  Reset_Sequence_to_Data( 'ACTIVITYLOG', 'LOGID' );
  Reset_Sequence_to_Data( 'JOBSTATE', 'JOBID' );
  Reset_Sequence_to_Data( 'BATCH', 'BATCHID' );

END Reset_All_Sequences;

내 실제 데이터베이스에는 이 메커니즘을 통해 재설정되는 다른 시퀀스가 ​​약 100개 있으므로 다음 호출이 97개 더 있습니다. Reset_Sequence_to_Data 위의 절차에서.

마음에 드시나요?싫다?무관심한?

alter sequence serial restart start with 0;

이 기능은 Oracle 12c의 새로운 기능입니다.그것은 ~ 아니다 에 포함 공식 문서.Oracle 패키지에서 생성된 스크립트에서 찾았습니다. DBMS_METADATA_DIFF.

경고: 저는 이 기능을 프로덕션 시스템에서 여러 번 사용해 왔으며 제 생각에는 임시 스크립트에서 이 명령을 사용하는 것이 괜찮다고 생각합니다.그러나 이를 애플리케이션의 일부로 프로시저에 포함시키고 싶지 않을 수도 있습니다.이 기능에 대해 묻는 Oracle 서비스 요청을 작성했습니다.이는 단순한 문서 버그가 아니라 지원되지 않는 기능입니다.다음과 같이 언젠가 명령이 사라질 수도 있습니다. WM_CONCAT.(그럴 가능성은 없다고 생각하지만 Oracle 구문은 거의 사라지지 않으며 내부적으로 최소한 두 곳 이상에서 사용되는 간단한 기능입니다.)

다음 스크립트는 시퀀스를 원하는 값으로 설정합니다.

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;
/

이것 저장 프로시저 내 시퀀스를 다시 시작합니다.

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;

/

Oracle에서 시퀀스를 재설정하는 또 다른 방법이 있습니다.설정 maxvalue 그리고 cycle 속성.때 nextval 시퀀스의 히트 maxvalue, 만약 cycle 속성이 설정된 다음부터 다시 시작됩니다. minvalue 시퀀스의.

음수 설정에 비해 이 방법의 장점 increment by 재설정 프로세스가 실행되는 동안 시퀀스를 계속 사용할 수 있으므로 재설정을 수행하기 위해 어떤 형태로든 중단이 발생할 가능성이 줄어듭니다.

다음에 대한 값 maxvalue 현재보다 커야 한다 nextval, 따라서 아래 절차에는 선택하는 사이에 시퀀스에 다시 액세스하는 경우 버퍼를 허용하는 선택적 매개 변수가 포함되어 있습니다. nextval 절차 및 설정에서 cycle 재산.

create sequence s start with 1 increment by 1;

select s.nextval from dual
connect by level <= 20;

   NEXTVAL
----------
         1 
...
        20

create or replace procedure reset_sequence ( i_buffer in pls_integer default 0)
as
  maxval pls_integer;
begin

  maxval := s.nextval + greatest(i_buffer, 0); --ensure we don't go backwards!
  execute immediate 'alter sequence s cycle minvalue 0 maxvalue ' || maxval;
  maxval := s.nextval;
  execute immediate 'alter sequence s nocycle maxvalue 99999999999999';

end;
/
show errors

exec reset_sequence;

select s.nextval from dual;

   NEXTVAL
----------
         1 

현재 상태의 절차에서는 다른 세션에서 값 0을 가져올 가능성이 허용되는데, 이는 문제가 될 수도 있고 아닐 수도 있습니다.그렇다면 언제든지 다음을 수행할 수 있습니다.

  • 세트 minvalue 1 첫 번째 변경에서
  • 두 번째 제외 nextval 술책
  • 문을 이동하여 설정 nocycle 나중에 실행되도록 다른 프로시저에 속성을 추가합니다(이 작업을 원한다고 가정).

맙소사, 이 모든 프로그래밍은 단지 인덱스 재시작을 위한 것입니다...아마도 나는 바보일지도 모르지만, Oracle 12 이전 버전(재시작 기능이 있음)의 경우 단순에 어떤 문제가 있습니까?

drop sequence blah;
create sequence blah 

?

1) 아래와 같이 SEQUENCE를 생성한다고 가정합니다.

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

2) 이제 SEQUENCE에서 값을 가져옵니다.아래와 같이 4번을 가져왔다고 가정해 보겠습니다.

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

3) 위의 4개 명령을 실행한 후 SEQUENCE의 값은 4가 됩니다.이제 SEQUENCE 값을 다시 1로 재설정했다고 가정합니다.다음 단계를 따르세요.아래 표시된 것과 동일한 순서로 모든 단계를 따르십시오.

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

시퀀스의 INCREMENT 값을 변경하고 증가시킨 다음 다시 변경하는 것은 매우 간단하며 시퀀스를 삭제/재생성했을 때처럼 모든 부여를 다시 설정할 필요가 없다는 추가 이점도 있습니다.

모든 시퀀스를 재설정하기 위해 블록을 만듭니다.

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;

다음은 시퀀스에서 반환된 다음 값을 변경하는 보다 강력한 절차와 그 외에도 훨씬 더 많은 것입니다.

  • 우선, 전달된 문자열 중 어느 것도 동적 SQL 문을 직접 생성하는 데 사용되지 않으므로 SQL 주입 공격으로부터 보호합니다.
  • 둘째, 다음 시퀀스 값이 최소 또는 최대 시퀀스 값의 범위를 벗어나 설정되는 것을 방지합니다.그만큼 next_value 될 것이다!= min_value 그리고 사이 min_value 그리고 max_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;

내 프로젝트에서 누군가가 시퀀스를 사용하지 않고 레코드를 수동으로 입력한 경우 시퀀스 값을 수동으로 재설정해야 했으며 이에 대해 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;

위의 코드는 시퀀스가 ​​지연되는 경우에도 작동합니다.

아래와 같이 CYCLE 옵션을 사용할 수 있습니다.

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

이 경우 시퀀스가 ​​MAXVALUE(100)에 도달하면 MINVALUE(0)로 재활용됩니다.

감소된 시퀀스의 경우 시퀀스는 MAXVALUE로 재활용됩니다.

모든 자동 증가 시퀀스를 실제 데이터와 일치시키는 방법은 다음과 같습니다.

  1. 이 스레드에서 이미 설명한 대로 다음 값을 적용하는 절차를 만듭니다.

    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;
    
  2. 모든 시퀀스를 실제 콘텐츠와 조정하는 다른 프로시저를 만듭니다.

    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;
    

노트:

  1. 프로시저가 트리거 코드에서 이름을 추출하고 명명 규칙에 의존하지 않습니다.
  2. 실행 전 생성된 코드를 확인하려면 마지막 두 줄의 주석을 전환하세요.

사용자가 값을 알 필요가 없고 시스템이 변수를 가져와 사용하여 업데이트하는 대안을 만듭니다.

--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;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top