Trong PostgreSQL , tôi có thể làm một cái gì đó như thế này:
ALTER SEQUENCE serial RESTART WITH 0;
Có tương đương với Oracle không?
Trong PostgreSQL , tôi có thể làm một cái gì đó như thế này:
ALTER SEQUENCE serial RESTART WITH 0;
Có tương đương với Oracle không?
Câu trả lời:
Đây là một quy trình tốt để đặt lại bất kỳ chuỗi nào về 0 từ guru Tom Kyte của Oracle . Thảo luận tuyệt vời về những ưu và nhược điểm trong các liên kết dưới đây quá.
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;
/
Từ trang này: SQL động để đặt lại giá trị chuỗi
Một cuộc thảo luận tốt khác cũng có ở đây: Làm cách nào để đặt lại chuỗi?
execute immediate
để nắm bắt đầu ra của một lựa chọn trả về tối đa 1 hàng. Dưới đây là tài liệu về thực thi ngay lập tức: docs.oracle.com/cd/B28359_01/appdev.111/b28370/ mẹo
'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
Một khởi động lại thực sự là không thể AFAIK . (Vui long sửa cho tôi nêu tôi sai!).
Tuy nhiên, nếu bạn muốn đặt thành 0, bạn chỉ cần xóa và tạo lại nó.
Nếu bạn muốn đặt giá trị cụ thể, bạn có thể đặt TĂNG thành giá trị âm và nhận giá trị tiếp theo.
Nghĩa là, nếu chuỗi của bạn ở mức 500, bạn có thể đặt nó thành 100 thông qua
ALTER SEQUENCE serial INCREMENT BY -400;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;
Đây là cách tiếp cận của tôi:
Thí dụ:
--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;
Tính năng này đã được thêm chính thức vào năm 18c nhưng không chính thức có sẵn trong 12.1.
Có thể sử dụng tính năng không có giấy tờ này trong 12.1. Mặc dù cú pháp không được bao gồm trong tài liệu chính thức , nó được tạo bởi gói Oracle DBMS_METADATA_DIFF . Tôi đã sử dụng nó nhiều lần trên các hệ thống sản xuất. Tuy nhiên, tôi đã tạo một yêu cầu Dịch vụ Oracle và họ đã xác minh rằng đó không phải là lỗi tài liệu, tính năng này thực sự không được hỗ trợ.
Trong 18c, tính năng này không xuất hiện trong Cú pháp ngôn ngữ SQL, nhưng được bao gồm trong Hướng dẫn của quản trị viên cơ sở dữ liệu .
... RESTART START WITH 0 MINVALUE 0
Cách tiếp cận của tôi là một phần mở rộng thiếu niên cho ví dụ của Dougman .
Tiện ích mở rộng là ...
Truyền vào giá trị hạt giống như một tham số. Tại sao? Tôi muốn gọi điều đặt lại chuỗi trở lại ID tối đa được sử dụng trong một số bảng . Tôi cuối cùng đã gọi Proc này từ một tập lệnh khác thực thi nhiều lệnh gọi cho một loạt các chuỗi, đặt lại giá trị tiếp theo xuống một mức đủ cao để không gây ra vi phạm khóa chính trong đó tôi đang sử dụng giá trị của chuỗi cho một mã định danh duy nhất.
Nó cũng tôn vinh giá trị tối thiểu trước đó . Trên thực tế, nó có thể đẩy giá trị tiếp theo cao hơn bao giờ nếu giá trị p_val hoặc giá trị hiện tại mong muốn cao hơn giá trị tiếp theo hiện tại hoặc được tính.
Tuyệt vời nhất, nó có thể được gọi để thiết lập lại một giá trị được chỉ định và chỉ cần đợi cho đến khi bạn thấy quy trình "sửa tất cả các chuỗi của tôi" ở cuối.
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;
Bản thân quy trình đó rất hữu ích, nhưng bây giờ chúng ta hãy thêm một quy trình khác gọi nó và chỉ định mọi thứ theo chương trình với quy ước đặt tên theo trình tự và tìm kiếm giá trị tối đa được sử dụng trong bảng / trường hiện có ...
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;
Bây giờ chúng tôi đang nấu ăn bằng gas!
Quy trình trên sẽ kiểm tra giá trị tối đa của một trường trong bảng, xây dựng tên chuỗi từ cặp bảng / trường và gọi "Reset_Sequence" với giá trị tối đa được cảm nhận đó.
Mảnh ghép cuối cùng trong câu đố này và lớp kem trên bánh tiếp theo ...
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;
Trong cơ sở dữ liệu thực tế của tôi, có khoảng một trăm trình tự khác được thiết lập lại thông qua cơ chế này, do đó, có thêm 97 cuộc gọi tới Reset_Sequence_to_Data trong quy trình đó ở trên.
Yêu nó? Ghét nó? Vô tư?
l_current
có thể là một trong những giá trị khác nhau, tùy thuộc vào nút nào mà tập lệnh được chạy; chạy lại tập lệnh có thể dẫn đến kết quả khác nhau. Tôi tìm thấy nếu tôi chạy nó nhiều lần thì cuối cùng nó cũng giải quyết được một giá trị cụ thể.
Kịch bản sau đây đặt chuỗi thành giá trị mong muốn:
Đưa ra một chuỗi mới được tạo có tên là PCS_PROJ_KEY_SEQ và bảng 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
từ khóa).
Thủ tục lưu trữ này khởi động lại trình tự của tôi:
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;
/
Có một cách khác để thiết lập lại một chuỗi trong Oracle: đặt các thuộc tính maxvalue
và cycle
. Khi nextval
chuỗi này chạm vào maxvalue
, nếu thuộc cycle
tính được đặt thì nó sẽ bắt đầu lại từ minvalue
chuỗi.
Ưu điểm của phương pháp này so với đặt âm increment by
là trình tự có thể tiếp tục được sử dụng trong khi quá trình đặt lại chạy, giảm khả năng bạn cần thực hiện một số hình thức ngừng hoạt động để thực hiện đặt lại.
Giá trị cho maxvalue
phải lớn hơn hiện tại nextval
, vì vậy quy trình bên dưới bao gồm một tham số tùy chọn cho phép bộ đệm trong trường hợp chuỗi được truy cập lại giữa việc chọn nextval
trong thủ tục và đặt thuộc cycle
tính.
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
Quy trình dưới dạng đứng yên cho phép khả năng phiên khác sẽ lấy giá trị 0, điều này có thể hoặc không phải là vấn đề đối với bạn. Nếu có, bạn luôn có thể:
minvalue 1
trong thay đổi đầu tiênnextval
tải thứ hainocycle
tính vào một thủ tục khác, sẽ được chạy vào một ngày sau đó (giả sử bạn muốn làm điều này).Jezus, tất cả các chương trình này chỉ để khởi động lại chỉ mục ... Có lẽ tôi là một thằng ngốc, nhưng đối với tiền truyện 12 (có tính năng khởi động lại), có gì sai với một simpel:
drop sequence blah;
create sequence blah
?
1) Giả sử bạn tạo một SEQUENCE như hiển thị bên dưới:
CREATE SEQUENCE TESTSEQ
INCREMENT BY 1
MINVALUE 1
MAXVALUE 500
NOCACHE
NOCYCLE
NOORDER
2) Bây giờ bạn lấy các giá trị từ SEQUENCE. Hãy nói rằng tôi đã lấy bốn lần như hình dưới đây.
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
SELECT TESTSEQ.NEXTVAL FROM dual
3) Sau khi thực hiện bốn lệnh trên, giá trị của SEQUENCE sẽ là 4. Bây giờ giả sử tôi đã đặt lại giá trị của SEQUENCE thành 1 lần nữa. Các bước sau đây. Thực hiện theo tất cả các bước theo cùng một thứ tự như dưới đây:
ALTER SEQUENCE TESTSEQ INCREMENT BY -3;
SELECT TESTSEQ.NEXTVAL FROM dual
ALTER SEQUENCE TESTSEQ INCREMENT BY 1;
SELECT TESTSEQ.NEXTVAL FROM dual
Việc thay đổi giá trị TĂNG CƯỜNG của chuỗi, tăng nó và sau đó thay đổi lại là khá đau đớn, cộng với bạn có thêm lợi ích là không phải thiết lập lại tất cả các khoản trợ cấp như bạn đã bỏ / tạo lại chuỗi.
Tôi tạo một khối để thiết lập lại tất cả các chuỗi của mình:
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;
Đây là một quy trình mạnh mẽ hơn để thay đổi giá trị tiếp theo được trả về bởi một chuỗi, cộng với nhiều hơn nữa.
next_value
sẽ được! = min_value
, Giữa min_value
và max_value
.increment_by
cài đặt hiện tại (hoặc được đề xuất) cũng như tất cả các cài đặt trình tự khác vào tài khoản khi dọn dẹp.ORA-01403: no data found
lỗi.Đây là mã:
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;
Trong dự án của tôi, một khi đã xảy ra việc ai đó nhập thủ công các bản ghi mà không sử dụng trình tự, do đó tôi phải đặt lại giá trị trình tự theo cách thủ công, mà tôi đã viết bên dưới đoạn mã 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;
Xin lưu ý, đoạn mã trên sẽ hoạt động nếu chuỗi bị trễ.
Bạn có thể sử dụng tùy chọn CYCLE, hiển thị bên dưới:
CREATE SEQUENCE test_seq
MINVALUE 0
MAXVALUE 100
START WITH 0
INCREMENT BY 1
CYCLE;
Trong trường hợp này, khi chuỗi đạt MAXVALUE (100), nó sẽ tái chế thành MINVALUE (0).
Trong trường hợp trình tự giảm dần, trình tự sẽ tái chế thành MAXVALUE.
Đây là cách làm cho tất cả các chuỗi tăng tự động khớp với dữ liệu thực tế:
Tạo một thủ tục để thực thi giá trị tiếp theo như đã được mô tả trong chuỗi này:
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;
Tạo một quy trình khác để điều hòa tất cả các chuỗi với nội dung thực tế:
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;
GHI CHÚ:
Tôi thực hiện một thay thế mà người dùng không cần biết các giá trị, hệ thống nhận và sử dụng các biến để cập nhật.
--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;
Thủ tục lưu trữ làm việc cho tôi
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;
Cách sử dụng thủ tục được lưu trữ:
execute reset_sequence('company_sequence','company');