Триггер Oracle: ВЫБРАТЬ В, данные не найдены - PullRequest
1 голос
/ 24 апреля 2020

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

CREATE TABLE elem_in_planet
(
    id_planet INTEGER,
    element_symbol CHAR(2),
    percent_representation NUMBER CONSTRAINT NN_elem_in_planet NOT NULL,

    CONSTRAINT PK_elem_in_planet PRIMARY KEY (id_planet, element_symbol),
    CONSTRAINT FK_planet_has_elem FOREIGN KEY (id_planet) REFERENCES planet (id_planet),
    CONSTRAINT FK_elem_in_planet FOREIGN KEY (element_symbol) REFERENCES chemical_element (element_symbol)
);

Я пытаюсь создать триггер, который предупреждает пользователей, когда они добавляют новый элемент до pl anet и сумма элементов в этом pl anet превышает 100%. Я придумал это.

CREATE OR REPLACE TRIGGER elem_in_planet_check
    AFTER INSERT OR UPDATE ON elem_in_planet
    FOR EACH ROW
DECLARE
    sum_var NUMBER;
    PRAGMA autonomous_transaction;
BEGIN
    SELECT SUM(percent_representation)
    INTO sum_var
    FROM elem_in_planet
    WHERE id_planet = :NEW.id_planet
    GROUP BY id_planet;

    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            sum_var := 0;

    IF sum_var > 100 THEN
        DBMS_OUTPUT.put_line('WARNING: Blah blah.');
    END IF;
END;
/

Этот код, кажется, вызывает исключение NO_DATA_FOUND каждый раз, даже если я вставил тестовые данные и когда я выполняю только запрос SQL, он работает как ожидалось.

Я новичок в этом и не понимаю, что делаю не так.

Спасибо за любой совет.

1 Ответ

1 голос
/ 25 апреля 2020

У вас НЕ вставлена ​​строка в таблицу, 2 причины.

  1. Триггер работает как часть оператора вставки, который не завершен. Таким образом, строка не существует.
  2. Вы указали «PRAGMA aut автономную_транзакцию» (AKA - оператор создания недопустимой ошибки здесь), ранее вы получали исключение мутирующей таблицы. Таким образом, вы не можете видеть какие-либо данные, вставленные / обновленные / удаленные текущей транзакцией. Кроме того, если ошибка все-таки произошла, строка все равно будет вставлена, поскольку вы не вызвали ошибку или не повторно подняли существующую ошибку. Предлагаю вам ознакомиться с блочной структурой PL SQL . На данный момент вы можете попробовать:

Вы можете использовать триггер после оператора или раздел оператора после сложного триггера, чтобы сделать этот тест, сделать Raire_application_error, если сумма> 100;

BTW в таком случае ваше «если на sum_var> 100» выполняется только при возникновении ошибки. Все, что находится после «ИСКЛЮЧЕНИЯ» и перед END для этого блока, выполняется только при возникновении ошибки.

create or replace trigger elem_in_planet_check
    after insert or update on elem_in_planet
declare 
   error_detected boolean := False;
begin
    for planet in 
        (
         select id_planet, sum_var
           from (select id_planet, sum(percent_representation) sum_var
                   from elem_in_planet
                  group by id_planet
                )
         where sum_var > 100
        )
    loop
       dbms_output.put_line('Planet ' || planet.id_planet || ' at '|| planet.sum_var || '% resources exceed 100%');  
       error_detected:= True; 
    end loop; 

    if error_detected then 
            Raise_application_error('-20001', 'Planet resources cannot exceed 100%'); 
    end if;

end elem_in_planet_check;
...