Oracle 9 - إعادة ضبط التسلسل ليتناسب مع حالة الجدول

StackOverflow https://stackoverflow.com/questions/1426647

  •  07-07-2019
  •  | 
  •  

سؤال

لدي تسلسل يستخدم لبذر مفاتيحي الأساسية (المعتمدة على عدد صحيح) في جدول أوراكل.

يبدو أن هذا التسلسل لم يتم استخدامه دائمًا لإدراج قيم جديدة في الجدول.كيف يمكنني استعادة التسلسل بما يتوافق مع القيم الفعلية في الجدول؟

هل كانت مفيدة؟

المحلول

إذا كان المعرف هو اسم عمود PK الخاص بك وكان PK_SEQ هو اسم التسلسل الخاص بك:

  1. أوجد قيمة أعلى PK بواسطة حدد الحد الأقصى (المعرف) من اسم الجدول

  2. أوجد قيمة PK_SEQ التالية ب حدد PK_SEQ. نكستفال من دوال

  3. إذا كان # 2 > # 1 ثم لا شيء يجب أن يكون تم ، على افتراض أنك تعامل هذه القيم كمفاتيح بديلة حقيقية
  4. وإلا، فقم بتغيير التسلسل إلى انتقل إلى الحد الأقصى للمعرف بواسطة ALTER SEQUENCE PK_SEQ الزيادة بمقدار [#1 القيمة - #2 القيمة]
  5. عثرة التسلسل بواسطة SELECT PK_SEQ. نكستفال من دوال

  6. إعادة تعيين قيمة زيادة التسلسل إلى 1 بواسطة PK_SEQ تسلسل ALTER زيادة بمقدار 1

يفترض كل هذا أنه ليس لديك إدراجات جديدة في الجدول أثناء قيامك بذلك...

نصائح أخرى

في قصيرة، لعبة ما يلي:

-- Current sequence value is 1000

ALTER SEQUENCE x INCREMENT BY -999;
Sequence altered.

SELECT X.NEXTVAL FROM DUAL;
1

ALTER SEQUENCE x INCREMENT BY 1;
Sequence altered.

ويمكنك الحصول على قيمة تسلسل ماكس المستخدمة في الجدول الخاص بك، تفعل الرياضيات، وتحديث تسلسل وفقا لذلك.

Declare
  difference INTEGER;
  sqlstmt varchar2(255);
  sequenceValue Number;
begin
sqlstmt := 'ALTER SEQUENCE YOURSEQUENCE INCREMENT BY ';
select YOURSEQUENCE.NEXTVAL into sequenceValue from dual;
select  (nvl(Max(YOURID),0) - sequenceValue)+1 into difference from YOURTABLE;
if difference > 0 then
  EXECUTE IMMEDIATE sqlstmt || difference;
  select  YOURSEQUENCE.NEXTVAL INTO sequenceValue from dual;
  EXECUTE IMMEDIATE sqlstmt || 1;
end if;
end;

وأنا جعلت هذا البرنامج النصي كما لم أجد السيناريو على الانترنت ان حيوي يحدد <م> جميع بلدي متواليات لأعلى ID الحالي. اختبارها على أوراكل 11.2.0.4.

DECLARE
  difference         INTEGER;
  sqlstmt            VARCHAR2(255) ;
  sqlstmt2           VARCHAR2(255) ;
  sqlstmt3           VARCHAR2(255) ;
  sequenceValue      NUMBER;
  sequencename       VARCHAR2(30) ;
  sequencelastnumber INTEGER;
  CURSOR allseq
  IS
     SELECT sequence_name, last_number FROM user_sequences ORDER BY sequence_name;
BEGIN
  DBMS_OUTPUT.enable(32000) ;
  OPEN allseq;
  LOOP
    FETCH allseq INTO sequencename, sequencelastnumber;
    EXIT
  WHEN allseq%NOTFOUND;
    sqlstmt  := 'ALTER SEQUENCE ' || sequencename || ' INCREMENT BY ';
    --Assuming: <tablename>_id is <sequencename>
    sqlstmt2 := 'select (nvl(Max(ID),0) - :1)+1 from ' || SUBSTR(sequencename, 1, LENGTH(sequencename) - 3) ;
    --DBMS_OUTPUT.PUT_LINE(sqlstmt2);
    --Attention: makes use of user_sequences.last_number --> possible cache problems!
    EXECUTE IMMEDIATE sqlstmt2 INTO difference USING sequencelastnumber;
    IF difference > 0 THEN
      DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt || difference) ;
      EXECUTE IMMEDIATE sqlstmt || difference;
      sqlstmt3 := 'SELECT ' || sequencename ||'.NEXTVAL from dual';
      DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt3 || ' INTO sequenceValue') ;
      EXECUTE IMMEDIATE sqlstmt3 INTO sequenceValue;
      DBMS_OUTPUT.PUT_LINE('EXECUTE IMMEDIATE ' || sqlstmt || 1) ;
      EXECUTE IMMEDIATE sqlstmt || 1;
      DBMS_OUTPUT.PUT_LINE('') ;
    END IF;
  END LOOP;
  CLOSE allseq;
END;

في بعض الحالات، قد تجد أنه من الأسهل لمجرد الحصول على قيمة الحد الأقصى الحالية ثم

drop sequence x;
create sequence x start with {current max + 1};

وسيتم تقسيم التطبيق بعد القيام الهبوط. ولكن من شأنها أن تبقي أي شخص من إدراج صفوف خلال تلك الفترة، وخلق تسلسل سريع. تأكد من إعادة أي المنح على تسلسل منذ سيتم إسقاط تلك عندما التسلسل. وقد ترغب في إعادة ترجمة أي plsql التي تعتمد على تسلسل يدويا.

وإضافة إلى https://stackoverflow.com/a/15929548/1737973 ، ولكن دون اللجوء إلى SEQUENCENAME.NEXTVAL بالتالي لا يؤدي في موقف واحد أكثر من ذلك يجب أن تكون:

DECLARE
  difference INTEGER;
  alter_sequence_statement VARCHAR2 (255);
  sequence_value NUMBER;
BEGIN
  --   Base for the statement that will set the sequence value.
  alter_sequence_statement :=
      'ALTER SEQUENCE SEQUENCENAME INCREMENT BY ';

  --   Fetch current last sequence value used.
  SELECT
    --   You could maybe want to make some further computations just
    -- below if the sequence is using caching.
    last_number
  INTO sequence_value
  FROM all_sequences
  WHERE sequence_owner = 'SEQUENCEOWNER' AND sequence_name = 'SEQUENCENAME';

  --   Compute the difference.
  SELECT max(id) - sequence_value + 1 INTO difference
  FROM SCHEMANAME.TABLENAME;

  IF difference <> 0 THEN
    --   Set the increment to a big offset that puts the sequence near
    -- its proper value.
    EXECUTE IMMEDIATE alter_sequence_statement || difference;

    --   This 'sequence_value' will be ignored, on purpose.
    SELECT SEQUENCENAME.NEXTVAL INTO sequence_value FROM dual;

    --   Resume the normal pace of incrementing one by one.
    EXECUTE IMMEDIATE alter_sequence_statement || 1;
  END IF;
END;

تنويه: إذا كان تسلسل يستخدم التخزين المؤقت (مجموعة all_sequences.cache_size إلى أكبر من 0) ربما كنت ترغب في أخذه بعين الاعتبار في احسب الفرق <م> الخطوة

وثائق Oracle لall sequences ... .

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top