Проблема с созданным триггером (последовательность первичных ключей)

Я создал последовательность, начинающуюся с 1 без максимального значения. Я создал триггер для вставки первичного ключа автоматически, что ниже. Я также установил ограничение для таблицы, в которой первичный ключ должен быть уникальным, а не нулевым.

create trigger MY_TEMP_TRIGGER
before insert on MY_TEMP
for each row

BEGIN

  SELECT MY_TEMP_SEQ.nextval 
    INTO :new.Id 
    FROM DUAL;

END;
/

INSERT INTO my_temp  
  (Id,Type, CreateDT, TypeId, TempType, DevType, Msg, File,User, Src, SrcDev)   
VALUES
 (MY_TEMP_SEQ.nextval,3434,2843,2453,2392,435,2390,'pension.txt','rereee',454545,3434)

Результат:

ОШИБКА в строке 1:
ORA-00001: уникальное ограничение (USER.PK_MY_TEMP) нарушено

Таблица MY_TEMP уже содержит значения от 1 до 338 для поля Id

Итак, как я должен обрабатывать это в триггерах и в моих операторах вставки.

3 ответа

Решение

Вы можете увеличить последовательность перед установкой триггера:

declare 
  v_max_id my_temp.id%type;
  v_curr_seq  NUMBER;
begin
  select max(id) into v_max_id from my_temp;

  loop
    select MY_TEMP_SEQ.nextval into v_curr_seq from dual;
    exit when v_curr_seq >= v_max_id;
  end loop;
end;
/

Если вы действительно хотите, чтобы опция указывала собственное значение идентификатора при вставке, а в другое время использовала триггер, используя последовательность, тогда ваш триггер должен проверить, было ли передано значение - в противном случае сгенерированный триггером идентификатор будет иметь приоритет (и если вы укажете MY_TEMP_SEQ.nextval во вставке это значение будет пропущено).

BEGIN
    IF :NEW.id IS NULL THEN
        SELECT MY_TEMP_SEQ.nextval 
        INTO :NEW.id 
        FROM DUAL;
    END IF;
END;

Работа с уже существующими ценностями сложнее. Если вы никогда не собираетесь передавать свое собственное (непоследовательное) значение идентификатора, тогда вы можете просто свернуть последовательность вперед до максимально возможного значения, например:

ALTER SEQUENCE MY_TEMP_SEQ INCREMENT BY 338; -- or however many you need to skip
SELECT MY_TEMP_SEQ.nextval FROM DUAL;
ALTER SEQUENCE MY_TEMP_SEQ INCREMENT BY 1;

Проблема может возникнуть в том случае, если вы попытаетесь вставить запись, указав значение идентификатора вручную, не используя последовательность, которая больше, чем последовательность (скажем, с использованием 500). Когда последовательность (в конце концов) достигнет этого значения, вы все равно получите ORA-00001.

Я не думаю, что вы можете справиться с этим или с вашей непосредственной проблемой в триггере; Я полагаю, что вы получите ошибку изменяющейся таблицы, если попытаетесь проверить существующее значение в той же таблице, и обходные пути для этого просто добавляют усложнение (требуется три триггера) и потенциально нестабильность. Насколько мне известно, единственный простой способ справиться с этим сценарием - это вместо этого вставить обертку в процедуру и заблокировать прямую вставку, что также может оказаться невозможным. Однако вам нужно беспокоиться об этом только в том случае, если вы когда-нибудь вставите значения без использования последовательности.

Вы не можете использовать оба - только один или другой.
В вашем примере id значение уже вставлено в качестве следующего значения последовательности... это то же значение, которое пытается использовать триггер. У меня может быть порядок в обратном порядке, но результат тот же.

Триггер не нужен, если вы будете ссылаться на последовательность в операторе INSERT:

INSERT INTO my_temp  
  (Id,Type, CreateDT, TypeId, TempType, DevType, Msg, File,User, Src, SrcDev)   
VALUES
  (MY_TEMP_SEQ.nextval,3434,2843,2453,2392,435,2390,'pension.txt','rereee',454545,3434);

Если использовать триггер

Наличие триггера означает, что вы не можете использовать id столбец в INSERT:

INSERT INTO my_temp  
  (Type, CreateDT, TypeId, TempType, DevType, Msg, File,User, Src, SrcDev)   
VALUES
  (3434, 2843, 2453, 2392, 435, 2390, 'pension.txt', 'rereee', 454545, 3434);

Больше всего нравится триггерный подход, потому что они используются либо для MySQL AUTOINCREMENT, либо для SQL Server IDENTITY (Denali, наконец, будет поддерживать последовательности ANSI).

Другие вопросы по тегам