2009-09-15 20 views
15

Tôi có một chuỗi được sử dụng để hạt giống các khóa chính (Integer based) của tôi trong một bảng oracle.Oracle 9 - Đặt lại trình tự để phù hợp với trạng thái của bảng

Dường như chuỗi này không phải lúc nào cũng được sử dụng để chèn các giá trị mới vào bảng. Làm thế nào để tôi nhận được trình tự trong bước với các giá trị thực tế trong bảng?

Trả lời

14

Nếu ID là tên của cột PK của bạn và PK_SEQ là tên của chuỗi của bạn:

  1. Tìm giá trị của PK cao nhất bởi CHỌN MAX (ID) TỪ tableName

  2. Tìm giá trị của PK_SEQ tiếp theo bằng cách CHỌN PK_SEQ.NEXTVAL FROM DUAL

  3. Nếu # 2> # 1 thì không có gì cần phải được thực hiện , giả sử bạn đối xử với những giá trị phím thay thế là đúng
  4. Nếu không, thay đổi trình tự để nhảy với ID max bởi ALTER SEQUENCE PK_SEQ tăng bởi [# 1 giá trị - # 2 value]
  5. Bump chuỗi bởi CHỌN PK_SEQ.NEXTVAL FROM DUAL

  6. Đặt lại chuỗi tăng giá trị tới 1 của ALTER sEQUENCE PK_SEQ ĐỘTĂNG bY 1

này tất cả các giả định rằng bạn không cần phải chèn mới vào bảng trong khi bạn đang làm điều này ...

+0

Tôi đang vật lộn với cách thực hiện bước 3, tôi đã thử các cú pháp khác nhau nhưng không thể làm việc đó – AJM

+2

Mục đích của bước 3 chỉ là so sánh giá trị PK lớn nhất với giá trị chuỗi tiếp theo. Vì vậy, ví dụ, nếu SELECT từ bước 1 dẫn đến kết quả là 100, và SELECT từ bước 2 dẫn đến kết quả là 90 có nghĩa là bạn có "nhảy" 11 chuỗi. Khi bạn thay đổi trình tự trong bước 4, lệnh SELECT ở bước 5 sẽ di chuyển 10 giá trị chuỗi, đến 100. Sau khi số dư được đặt lại ở bước 6, "SELECT PK_SEQ.NEXTVAL FROM DUAL" tiếp theo sẽ cho bạn 101. – dpbradley

+0

Trong Bước 4 Tôi không thể có cú pháp để thực hiện phép trừ trong mệnh đề Increment by. Tôi đã thử [a-b] a-b và selecr a-b từ đôi, nhưng không thành công. – AJM

11

Nói tóm lại, trò chơi nó:

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

Bạn có thể nhận được giá trị chuỗi tối đa sử dụng trong bảng của bạn, làm toán, và cập nhật các trình tự phù hợp.

+0

Trợ giúp này như thế nào. Nếu id tối đa trong bảng là 624. Làm thế nào là ở trên sẽ thiết lập chính xác seq? – ginalster

0

Trong một số trường hợp, bạn có thể tìm thấy nó dễ dàng hơn để chỉ đơn giản là có được giá trị tối đa hiện tại và sau đó

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

Ứng dụng sẽ bị hỏng sau khi bạn thực hiện thao tác thả. Nhưng điều đó sẽ giữ cho mọi người không chèn hàng trong suốt thời gian đó và tạo chuỗi nhanh. Hãy chắc chắn rằng bạn tạo lại bất kỳ khoản trợ cấp nào trên chuỗi vì những thứ đó sẽ bị xóa khi chuỗi được thực hiện. Và bạn có thể muốn tự biên dịch lại bất kỳ plsql nào phụ thuộc vào trình tự.

+2

@Jim - Tôi sẽ tránh bỏ bất kỳ đối tượng db nếu có một thay thế. Việc giảm trình tự sẽ không nhất thiết ngăn các chèn trên bảng không tham chiếu trình tự. Như bạn chỉ ra bạn cũng có thêm công việc chụp các khoản tài trợ và biên dịch lại các đối tượng phụ thuộc. – dpbradley

8
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; 
+1

Điều này đặt nó 1 ở trên mà nó phải là ... – Worthy7

+0

Tôi nghĩ rằng đó là vì 'chọn YOURSEQUENCE.NEXTVAL vào sequenceValue từ kép;' ở dòng 7, bạn có thể kiểm tra một thay thế cho nó tại câu trả lời của tôi tại [https://stackoverflow.com/a/45542069/1737973](https://stackoverflow.com/a/45542069/1737973), tìm nạp 'all_sequences.last_number WHERE sequence_name = 'YOURSEQUENCE'' thay vì' YOURSEQUENCE.NEXTVAL', có thể nhận được giá trị mong muốn _given giá trị chuỗi bộ nhớ đệm bị vô hiệu hóa_. – uprego

4

tôi đã thực hiện kịch bản này như tôi đã không tìm thấy một kịch bản trực tuyến mà tự động đặt tất cả chuỗi của tôi để ID cao nhất hiện nay. Thử nghiệm trên Oracle 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; 
0

Thêm lên đến https://stackoverflow.com/a/15929548/1737973, nhưng mà không cần đến SEQUENCENAME.NEXTVAL do đó không dẫn đến một vị trí trên nó nên là:

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; 

Disclaimer: nếu chuỗi được sử dụng bộ nhớ đệm (all_sequences.cache_size thiết lập để lớn hơn 0) bạn có thể muốn xem xét trong số Tính toán sự khác biệt bước.

Oracle documentation for all sequences....

+0

Oh well, xin lỗi này là dành cho Oracle 11, tôi không biết nếu nó có thể làm việc trong Oracle 9 mà không có thay đổi. – uprego

Các vấn đề liên quan