Ошибка триггера pl/sql: точная выборка возвращает больше запрошенного количества строк

Мне трудно понять, что не так с моим триггером pl/sql. Ошибка: Отчет об ошибке - Ошибка SQL: ORA-01422: точная выборка возвращает больше запрошенного числа строк ORA-06512: в "SYSTEM.TRG_LATE_RETURN", строка 6 ORA-04088: ошибка во время выполнения триггера "SYSTEM.TRG_LATE_RETURN' 01422. 00000 - "Точная выборка возвращает больше запрошенного количества строк" ​​* Причина: число, указанное в точной выборке, меньше возвращаемых строк. * Действие: переписать запрос или изменить количество запрошенных строк

Мой триггер выглядит следующим образом:

create or replace trigger trg_late_return
before update of DETAIL_RETURNDATE, DETAIL_DUEDATE on TY_DETAILRENTAL

declare 
  temp_date DATE:= SYSDATE;
  temp_due_date DATE:= SYSDATE;

BEGIN
  select DETAIL_RETURNDATE
  into temp_date
  from TY_DETAILRENTAL;

  select DETAIL_DUEDATE
  into temp_due_date
  from TY_DETAILRENTAL;

  IF temp_date is null
  THEN
    update TY_DETAILRENTAL
    set DETAIL_DAYSLATE=null;
  END IF;

  if temp_date <> null
  THEN
    if temp_date = trunc(temp_due_date) + 1
    then
      update TY_DETAILRENTAL
      set DETAIL_DAYSLATE=0;
    end if;

    if temp_date > trunc(temp_due_date) + 1
    then
      update TY_DETAILRENTAL
      set DETAIL_DAYSLATE = DETAIL_RETURNDATE - DETAIL_DUEDATE;
    end if;  
  end if;

END;
/ 

Новичок в SQL и PL/SQL, поэтому я был бы признателен за любую помощь.

1 ответ

Решение

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

Триггер также работает с той же таблицей, которую вы запрашиваете и обновляете, что говорит о том, что вы на самом деле подразумевали, что это (или нужно, чтобы это было) триггер уровня строки, а не триггер уровня оператора.

Это означает, что вам нужно добавить for each row к определению, и вместо того, чтобы запрашивать и обновлять таблицу, вы можете работать с new псевдозапись, доступная для триггеров уровня строки.

Вы также не можете использовать <> сравнить с нулем; вы уже используете is nullи противоположность этому is not null, Хотя вы могли бы просто использовать else Вот.

Так что это может быть то, что вы хотели:

create or replace trigger trg_late_return
before update of detail_returndate, detail_duedate
on ty_detailrental
for each row
begin
  if :new.detail_returndate is null
  then
    :new.detail_dayslate := null;
  else
    if :new.detail_returndate = trunc(:new.detail_duedate) + 1
    then
      :new.detail_dayslate := 0;
    elsif :new.detail_returndate > trunc(:new.detail_duedate) + 1
    then
      :new.detail_dayslate := :new.detail_returndate - :new.detail_duedate;
    end if;  
  end if;
end;
/

Вы можете обратиться к обновленному значению столбцов с помощью :new при их сравнении, так что вам не нужны копии локальных переменных этих значений. (Вы можете посмотреть на значения перед обновлением с :old тоже, но в этом нет необходимости).

Изменения, которые вы вносите в new псевдозапись используется, когда фактическая совпадающая строка в базе данных наконец обновляется.

Узнайте больше о новых / старых псевдозаписях и о триггерах в целом.

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