Подтвердить что ты не робот

Лучший способ reset последовательности Oracle для следующего значения в существующем столбце?

По какой-то причине люди в прошлом вставляли данные без использования последовательности. NEXTVAL. Поэтому, когда я иду использовать sequence.NEXTVAL, чтобы заполнить таблицу, я получаю нарушение PK, так как это число уже используется в таблице.

Как обновить следующее значение, чтобы оно было пригодным для использования? Прямо сейчас, я просто вставляю снова и снова, пока он не будет успешным (INSERT INTO tbl (pk) VALUES (sequence.NEXTVAL)), и это синхронизирует следующий номер.

4b9b3361

Ответ 1

Эти две процедуры позволяют мне reset последовательность и reset последовательность, основанную на данных в таблице (извинения за соглашения о кодировании, используемые этим клиентом):

CREATE OR REPLACE PROCEDURE SET_SEQ_TO(p_name IN VARCHAR2, p_val IN NUMBER)
AS
   l_num   NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;

   -- Added check for 0 to avoid "ORA-04002: INCREMENT must be a non-zero integer"
   IF (p_val - l_num - 1) != 0
   THEN
      EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by ' || (p_val - l_num - 1) || ' minvalue 0';
   END IF;

   EXECUTE IMMEDIATE 'select ' || p_name || '.nextval from dual' INTO l_num;

   EXECUTE IMMEDIATE 'alter sequence ' || p_name || ' increment by 1 ';

   DBMS_OUTPUT.put_line('Sequence ' || p_name || ' is now at ' || p_val);
END;

CREATE OR REPLACE PROCEDURE SET_SEQ_TO_DATA(seq_name IN VARCHAR2, table_name IN VARCHAR2, col_name IN VARCHAR2)
AS
   nextnum   NUMBER;
BEGIN
   EXECUTE IMMEDIATE 'SELECT MAX(' || col_name || ') + 1 AS n FROM ' || table_name INTO nextnum;

   SET_SEQ_TO(seq_name, nextnum);
END;

Ответ 2

Вы можете временно увеличить размер кеша и выбрать один фиктивный выбор, а затем reset размер кэша до 1. Итак, например

ALTER SEQUENCE mysequence INCREMENT BY 100;

select mysequence.nextval from dual;

ALTER SEQUENCE mysequence INCREMENT BY 1;

Ответ 3

Если вы можете рассчитывать на период времени, когда таблица находится в стабильном состоянии без новых вставок, это должно сделать это (непроверено):

DECLARE
  last_used  NUMBER;
  curr_seq   NUMBER;
BEGIN
  SELECT MAX(pk_val) INTO last_used FROM your_table;

  LOOP
    SELECT your_seq.NEXTVAL INTO curr_seq FROM dual;
    IF curr_seq >= last_used THEN EXIT;
    END IF;
  END LOOP;
END;

Это позволяет вам синхронизировать последовательность с таблицей, не отбрасывая/воссоздавая/повторно предоставляя последовательность. Он также не использует DDL, поэтому никаких неявных коммитов не выполняется. Конечно, вам придется выследить и пощекотать людей, которые настаивают на том, чтобы не использовать последовательность, чтобы заполнить столбец...

Ответ 4

С оракулом 10.2g:

select  level, sequence.NEXTVAL
from  dual 
connect by level <= (select max(pk) from tbl);

задает текущее значение последовательности max (pk) вашей таблицы (т.е. следующий вызов NEXTVAL даст вам правильный результат); если вы используете Toad, нажмите F5, чтобы запустить оператор, а не F9, который выводит на выход (таким образом, останавливая приращение после, обычно, 500 строк). Хорошая сторона: это решение - это только DML, а не DDL. Только SQL и PL-SQL. Плохая сторона: это решение печатает строки вывода max (pk), то есть обычно медленнее, чем решение ALTER SEQUENCE.

Ответ 5

В моем случае у меня есть последовательность с именем PS_LOG_SEQ, которая имела LAST_NUMBER = 3920.

Затем я импортировал некоторые данные из PROD на свою локальную машину и вставил в таблицу PS_LOG. Производственные данные имели более чем 20000 строк с последним LOG_ID (первичным ключом) - 20070. После импорта я попытался вставить новые строки в эту таблицу, но при сохранении я получил исключение, подобное этому:

ORA-00001: unique constraint (LOG.PS_LOG_PK) violated

Несомненно, это связано с последовательностью PS_LOG_SEQ, связанной с таблицей PS_LOG. LAST_NUMBER сталкивался с импортированными данными, которые уже использовали следующее значение ID из PS_LOG_SEQ.

Чтобы решить эту проблему, я использовал эту команду для обновления последовательности до последней версии \ max(LOG_ID) + 1:

alter sequence PS_LOG_SEQ restart start with 20071;

Эта команда reset значение LAST_NUMBER, и я мог бы затем вставить новые строки в таблицу. Больше никаких столкновений.:)

Примечание: эта команда alter sequence является новой в Oracle 12c.