답변:
다음은 Oracle guru 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
또 다른 좋은 논의는 다음과 같습니다. 시퀀스를 재설정하는 방법?
execute immediate
최대 1 행을 리턴하는 선택의 출력을 캡처하는 데 사용할 때 사용되는 구문 입니다. 다음은 즉시 실행에 대한 설명서는 다음과 같습니다 docs.oracle.com/cd/B28359_01/appdev.111/b28370/...
'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
진정한 재시작은 불가능합니다 AFAIK . (내가 틀렸다면 나를 정정하십시오!).
그러나 0으로 설정하려면 삭제하고 다시 만들면됩니다.
특정 값으로 설정하려면 INCREMENT를 음수 값으로 설정하고 다음 값을 얻을 수 있습니다.
즉, 시퀀스가 500 인 경우 다음을 통해 시퀀스를 100으로 설정할 수 있습니다.
ALTER SEQUENCE serial INCREMENT BY -400;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;
이것은 내 접근 방식입니다.
예:
--Drop sequence
DROP SEQUENCE MY_SEQ;
-- Create sequence
create sequence MY_SEQ
minvalue 1
maxvalue 999999999999999999999
start with 1
increment by 1
cache 20;
alter sequence serial restart start with 1;
이 기능은 공식적으로 18c에 추가되었지만 12.1에서는 비공식적으로 제공됩니다.
이 문서화되지 않은 기능을 12.1에서 사용하는 것이 틀림없이 안전합니다. 구문은 공식 문서에 포함되어 있지 않지만 Oracle 패키지 DBMS_METADATA_DIFF에 의해 생성됩니다 . 프로덕션 시스템에서 여러 번 사용했습니다. 그러나 Oracle Service 요청을 작성했으며 설명서 버그가 아닌지 확인했으며이 기능은 실제로 지원되지 않습니다.
18c에서이 기능은 SQL 언어 구문에는 나타나지 않지만 데이터베이스 관리자 안내서에 포함되어 있습니다.
... RESTART START WITH 0 MINVALUE 0
내 접근 방식은 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;
그 절차는 그 자체로 유용하지만 이제는 그것을 명명하고 시퀀스 명명 규칙을 사용하여 프로그래밍 방식으로 모든 것을 지정하고 기존 테이블 / 필드에서 사용되는 최대 값을 찾는 다른 것을 추가합시다 ...
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;
이제 우리는 가스로 요리하고 있습니다!
위의 절차는 테이블에서 필드의 최대 값을 확인하고 테이블 / 필드 쌍에서 시퀀스 이름을 작성하고 감지 된 최대 값으로 "Reset_Sequence" 를 호출 합니다.
이 퍼즐의 마지막 조각과 케이크의 장식은 다음에옵니다 ...
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 개의 다른 시퀀스가 있으므로 위의 해당 절차에서 Reset_Sequence_to_Data 에 대한 97 개의 호출이 더 있습니다.
좋아? 싫다? 무관심한?
l_current
수 있다는 것입니다. 여기서 스크립트가 실행되는 노드에 따라 다양한 값 중 하나 일 수 있습니다. 스크립트를 다시 실행하면 다른 결과가 발생할 수 있습니다. 여러 번 실행하면 결국 특정 값으로 설정되었습니다.
다음 스크립트는 시퀀스를 원하는 값으로 설정합니다.
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;
/
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
나중에 실행되도록 속성을 다른 프로 시저로 설정하기 위해 명령문을 이동하십시오 (이를 원한다고 가정).Jezus, 인덱스 재시작을위한이 모든 프로그래밍 ... 아마도 바보 일지 모르지만, Oracle 12 이전 버전 (다시 시작 기능이 있음)의 경우 simpel의 문제점은 무엇입니까?
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로 다시 설정했다고 가정합니다. 다음 단계를 따르십시오. 아래에 표시된 순서대로 모든 단계를 수행하십시오.
ALTER SEQUENCE TESTSEQ INCREMENT BY -3;
SELECT TESTSEQ.NEXTVAL FROM dual
ALTER SEQUENCE TESTSEQ INCREMENT BY 1;
SELECT TESTSEQ.NEXTVAL FROM dual
모든 시퀀스를 재설정하는 블록을 만듭니다.
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;
다음은 시퀀스에 의해 반환 된 다음 값과 훨씬 더 많은 값을 변경하는보다 강력한 절차입니다.
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;
내 프로젝트에서 누군가 시퀀스를 사용하지 않고 수동으로 레코드를 입력 한 경우 시퀀스 값을 수동으로 재설정해야합니다.
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로 재순환됩니다.
모든 자동 증가 시퀀스를 실제 데이터와 일치시키는 방법은 다음과 같습니다.
이 스레드에서 이미 설명한대로 다음 값을 적용하는 프로 시저를 작성하십시오.
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;
노트:
사용자가 값을 알 필요가 없으며 시스템이 변수를 가져 와서 업데이트하는 대안을 만듭니다.
--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;
나를 위해 일한 저장 프로 시저
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');