ฉันจะรีเซ็ตลำดับใน Oracle ได้อย่างไร


170

ในPostgreSQLฉันสามารถทำสิ่งนี้:

ALTER SEQUENCE serial RESTART WITH 0;

มี Oracle เทียบเท่าหรือไม่


1
มีลักษณะที่ "ตั้งค่าลำดับว่า" ที่นี่
gerikson

3
คำเตือน: รหัสทั้งหมดด้านล่างใช้ได้เฉพาะกับลำดับที่สร้างขึ้นครั้งแรกด้วย "การเพิ่มทีละ 1" หากลำดับต้นฉบับถูกสร้างขึ้นพร้อมส่วนเพิ่ม! = 1; หลังจากใช้ขั้นตอนใด ๆ ข้างต้นการเพิ่มจะเปลี่ยนเป็น 1! ค่าการเพิ่มที่ถูกต้องที่จะใช้สามารถรับได้จากมุมมอง user_sequences

1
วางและสร้างลำดับใหม่อีกครั้ง
Viswanath Lekshmanan

คำตอบ:


153

นี่คือขั้นตอนที่ดีสำหรับการตั้งค่าลำดับใด ๆ ถึง 0 จาก Oracle guru ทอม Kyte การอภิปรายที่ดีเกี่ยวกับข้อดีข้อเสียในลิงค์ด้านล่างด้วย

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: สวัสดีผมเป็นผู้เริ่มต้น .... ในคำตอบข้างต้นทำไมคุณพูดถึงคำสั่งในส่วนสุดท้ายแทนดำเนินการทันที 'เลือก' | | p_seq_name || '.nextval INTO l_val จากคู่';
Thiyagu ATR

@Thiyagu: ใน PL / SQL นี่คือไวยากรณ์เมื่อใช้execute immediateเพื่อจับภาพผลลัพธ์ของตัวเลือกที่ส่งคืนได้มากที่สุด 1 แถว นี่คือเอกสารเกี่ยวกับการดำเนินการทันที: docs.oracle.com/cd/B28359_01/appdev.111/b28370/…
Doug Porter

@matra ฉันไม่เห็นสถานการณ์ที่จะต้องรีเซ็ตลำดับและอยู่ในสภาพแวดล้อมที่เกิดขึ้นพร้อมกันกับผู้ใช้รายอื่นในลำดับเดียวกัน
Ekevoo

ทำไมคุณต้องเลือกลำดับทำไมไม่ทำแค่บรรทัดสุดท้าย'alter sequence ' || p_seq_name || ' increment by 1 minvalue 0';
Goku

100

รีสตาร์ทจริงเป็นไปไม่ได้AFAIK (โปรดแก้ไขฉันถ้าฉันผิด!)

อย่างไรก็ตามหากคุณต้องการตั้งค่าเป็น 0 คุณสามารถลบและสร้างใหม่ได้

หากคุณต้องการตั้งเป็นค่าเฉพาะคุณสามารถตั้งค่า INCREMENT ให้เป็นค่าลบและรับค่าถัดไป

นั่นคือถ้าลำดับของคุณอยู่ที่ 500 คุณสามารถตั้งค่าเป็น 100 ผ่าน

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

4
เพียงทราบสำหรับคนใน PLSQL อย่าลืมเพิ่ม "ขีด จำกัด 1;" หรือ "rownum = 1" ไปยังคำสั่ง select มิฉะนั้นคุณสามารถจบการทำงาน next ถัดไปได้สองสามครั้งและเพิ่มขึ้นอีก -400 อย่างไรก็ตามหลายครั้ง
user830914

1
ลำดับข้อผิดพลาด. NEXTVAL ต่ำกว่า MINVALUE และไม่สามารถสร้างอินสแตนซ์ได้เมื่อ INCREMENT BY - <<big_number>>
zloctb

47

นี่คือแนวทางของฉัน:

  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;

29
เพิ่งทราบว่าการดรอปจะทำให้วัตถุใด ๆ ที่ขึ้นกับลำดับนั้นเป็นโมฆะและพวกเขาจะต้องคอมไพล์ใหม่
Doug Porter

22
นอกจากนี้คุณจะต้องให้สิทธิ์ใด ๆ ที่ได้รับจากการเลือกอีกครั้ง
GreenGiant

37
alter sequence serial restart start with 1;

คุณลักษณะนี้ได้รับการเพิ่มอย่างเป็นทางการใน 18c แต่ไม่สามารถใช้ได้อย่างเป็นทางการใน 12.1

มีความปลอดภัยในการใช้คุณลักษณะที่ไม่มีเอกสารนี้ใน 12.1 แม้ว่าไวยากรณ์จะไม่รวมอยู่ในเอกสารที่เป็นทางการก็ถูกสร้างขึ้นโดยแพคเกจออราเคิลDBMS_METADATA_DIFF ฉันใช้มันหลายครั้งกับระบบการผลิต อย่างไรก็ตามฉันสร้างคำขอ Oracle Service และพวกเขาตรวจสอบว่าไม่ใช่ข้อผิดพลาดของเอกสารคุณลักษณะไม่ได้รับการสนับสนุนอย่างแท้จริง

ใน 18C คุณลักษณะไม่ปรากฏในภาษา SQL ไวยากรณ์ แต่จะรวมอยู่ในคู่มือผู้ดูแลระบบฐานข้อมูลของ


สวัสดี @ จอนฉันตระหนักถึงคุณลักษณะที่ไม่มีเอกสารอย่างไรก็ตามฉันไม่ทราบว่ามีการเห็นในสคริปต์ที่สร้างขึ้นจาก DBMS_METADATA_DIFF คุณช่วยให้ฉันรู้ว่าคุณสร้างสคริปต์ขั้นตอนอื่น ๆ ได้อย่างไร? ฉันจะลองทดสอบด้วย
Lalit Kumar B

@LalitKumarB ฉันสะดุดกับคุณลักษณะนั้นในขณะที่ตอบคำถามนี้
Jon Heller

1
อ่าเข้าใจแล้วตอนนี้ ขอบคุณ :-)
Lalit Kumar B

ฉันเดาว่าสิ่งนี้ถูกนำมาใช้เพื่อสนับสนุน "แก้ไขตาราง your_table แก้ไข (id ที่สร้างขึ้นโดยค่าเริ่มต้นเป็นโมฆะเป็นตัวตนเริ่มต้นด้วยค่า จำกัด );" ดีใจที่ได้รู้ว่ามันทำงานในลำดับมาตรฐานด้วยเช่นกัน!
โอลิเวอร์

1
ในกรณีที่ค่าต่ำสุดของภาคต่อมีค่ามากกว่า 0 ลองเขียน... RESTART START WITH 0 MINVALUE 0
conceptdeluxe

33

แนวทางของฉันคือการขยายตัวอย่างเล็ก ๆของดั๊กแมน

ส่วนขยายคือ ...

ส่งผ่านค่าเมล็ดเป็นพารามิเตอร์ ทำไม? ฉันชอบที่จะเรียกสิ่งรีเซ็ตลำดับกลับไปยังหมายเลขที่ใช้สูงสุดในตารางบาง ฉันลงเอยด้วยการเรียก proc นี้จากสคริปต์อื่นซึ่งดำเนินการเรียกหลาย ๆ ครั้งสำหรับการเรียงลำดับทั้งกลุ่มการรีเซ็ตค่า nextval กลับไปสู่ระดับหนึ่งซึ่งสูงพอที่จะไม่ทำให้เกิดการละเมิดคีย์หลักที่ฉันใช้ค่าลำดับสำหรับตัวระบุเฉพาะ

นอกจากนี้ยังได้รับเกียรตินิยมก่อนMINVALUE ในความเป็นจริงอาจผลักดันค่าถัดไปสูงกว่าที่เคยถ้าp_valที่ต้องการหรือminvalue ที่มีอยู่สูงกว่าค่าถัดไปปัจจุบันหรือการคำนวณ

ดีที่สุดของทั้งหมดมันสามารถถูกเรียกให้รีเซ็ตเป็นค่าที่ระบุและเพียงแค่รอจนกว่าคุณจะเห็นขั้นตอนการ "แก้ไขลำดับของฉันทั้งหมด" ตอนท้าย

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;

ในฐานข้อมูลจริงของฉันมีลำดับประมาณหนึ่งร้อยลำดับที่ถูกรีเซ็ตผ่านกลไกนี้ดังนั้นจึงมีการเรียกไปที่Reset_Sequence_to_Dataอีก 97 ครั้งในขั้นตอนนั้น

รักเหรอ? เกลียดมัน? ไม่แยแส?


2
ฉันรักมัน. ฉันจะเพิ่มตัวแปรเพื่อรับและบันทึกการเพิ่มขึ้นตามมูลค่าจากตาราง user_sequences (อาจไม่ใช่ 1) หมายเหตุ: อาจต้องใช้ตาราง all_sequences แทน ในกรณีนี้คุณอาจต้องการส่งผ่านใน sequence_owner เช่นกัน
Harv

1
ไม่สามารถโหวตคุณได้มากพอ นี่เป็นปัญหาที่พบได้บ่อยเมื่อคุณจัดการกับการย้ายข้อมูลและนี่เป็นวิธีที่ดีที่สุด AFAIK หากคุณติดอยู่กับลำดับ
Dominique Eav

1
เพิ่มขึ้นเพราะนี่เป็นวิธีการที่ยอดเยี่ยม ข้อเสียเพียงอย่างเดียวคือมันสามารถส่งผลให้เกิดพฤติกรรมที่คาดเดาไม่ได้ในระบบ RAC ซึ่งl_currentอาจเป็นหนึ่งในค่าต่างๆขึ้นอยู่กับโหนดที่สคริปต์จะทำงาน; การเรียกใช้สคริปต์อีกครั้งอาจส่งผลให้เกิดผลลัพธ์ที่แตกต่างกัน ฉันพบว่าฉันวิ่งไปหลายครั้งในที่สุดก็ตัดสินโดยใช้ค่าเฉพาะ
Jeffrey Kemp

10

สคริปต์ต่อไปนี้ตั้งค่าลำดับเป็นค่าที่ต้องการ:

กำหนดลำดับที่สร้างขึ้นใหม่ชื่อ 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;
/

1
คุณลืมเครื่องหมายลบในคำสั่ง DDL แรกของคุณ (เช่นกันมีENDคำหลักเพิ่มเติม)
Priidu Neemre

5

โพรซีเดอร์ที่เก็บนี้รีสตาร์ทลำดับของฉัน:

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

4

มีอีกวิธีในการรีเซ็ตลำดับใน 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คุณสมบัติเป็นโพรซีเดอร์อื่นเพื่อให้รันได้ในภายหลัง

3

Jezus การเขียนโปรแกรมทั้งหมดนี้เป็นเพียงการเริ่มต้นดัชนี ... บางทีฉันอาจเป็นคนงี่เง่า แต่สำหรับ pre-oracle 12 (ซึ่งมีคุณสมบัติการรีสตาร์ท) สิ่งที่ผิดปกติกับ SIMPEL:

drop sequence blah;
create sequence blah 

?


2
ปัญหาหลักของการดรอปลำดับคือการสูญเสียสิทธิ์ที่ได้รับ
Jon Heller

1
ตกลงรับจอน ส่วนใหญ่การกู้คืนเหล่านี้จะใช้เวลาน้อยกว่าการเขียนโปรแกรมนั้นทั้งหมด DBA ดีมักจะมีสคริปต์เพื่อที่ไม่ควรจะเป็นปัญหา :-)
อเรนซ์

2

1) สมมติว่าคุณสร้างลำดับตามที่แสดงด้านล่าง:

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 อีกครั้ง ทำตามขั้นตอนต่อไปนี้ ทำตามขั้นตอนทั้งหมดในลำดับเดียวกันตามที่แสดงด้านล่าง:

  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

2

การเปลี่ยนแปลงค่า INCREMENT ของลำดับเพิ่มขึ้นแล้วเปลี่ยนกลับเป็นค่าที่ไม่เจ็บปวดและคุณจะได้รับประโยชน์เพิ่มเติมโดยไม่ต้องสร้างทุนทั้งหมดอีกครั้งตามที่คุณต้องการให้คุณลบ / สร้างลำดับขึ้นใหม่


2

ฉันสร้างบล็อกเพื่อรีเซ็ตลำดับทั้งหมดของฉัน:

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;

2

นี่คือขั้นตอนที่มีประสิทธิภาพมากขึ้นสำหรับการแก้ไขค่าถัดไปที่ส่งคืนโดยลำดับรวมทั้งอีกมาก

  • ก่อนอื่นมันจะป้องกันการโจมตีจากการฉีด 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;

2

ในโครงการของฉันเมื่อเกิดขึ้นว่ามีคนป้อนข้อมูลด้วยตนเองโดยไม่ใช้ลำดับดังนั้นฉันต้องรีเซ็ตค่าลำดับด้วยตนเองซึ่งฉันเขียนข้อมูลโค้ด 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;

โปรดทราบรหัสข้างต้นจะใช้งานได้หากลำดับมีความล่าช้า


1

คุณสามารถใช้ตัวเลือก CYCLE ที่แสดงด้านล่าง:

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

ในกรณีนี้เมื่อลำดับถึง MAXVALUE (100) มันจะรีไซเคิลไปยัง MINVALUE (0)

ในกรณีของลำดับที่ลดลงลำดับจะรีไซเคิลไปยัง MAXVALUE


1
สำหรับ downvoters (ใครจะไม่เห็นความคิดเห็นนี้): แอตทริบิวต์ CYCLE เป็นสิ่งที่ฉันใช้เพื่อให้การรีเซ็ตตามลำดับสำเร็จ ความจริงที่ว่าการรีเซ็ตเป็นแบบอัตโนมัติไม่ได้หมายความว่ามันจะไม่บรรลุเป้าหมาย - OP ไม่ได้ระบุว่าการรีเซ็ตจะต้องเป็นลำดับที่มีอยู่ก่อน !
Jeromy French

1

นี่คือวิธีการทำให้ลำดับการเพิ่มอัตโนมัติทั้งหมดตรงกับข้อมูลจริง:

  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. ในการตรวจสอบรหัสที่สร้างขึ้นก่อนการดำเนินการให้สลับความคิดเห็นในสองบรรทัดสุดท้าย

1

ฉันสร้างทางเลือกที่ผู้ใช้ไม่จำเป็นต้องรู้ค่าระบบรับและใช้ตัวแปรเพื่ออัปเดต

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

-1

ขั้นตอนการจัดเก็บที่เหมาะกับฉัน

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');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.