У меня есть код запуска, который только что печатает сообщения и интригует меня. У меня нет другого триггера, связанного с этой таблицей (я делаю таблицу сбрасывания, чтобы усилить ее), но когда первый триггер срабатывает в первый раз (первая вставка на таблицу), возникает следующее поведение:Сложный триггер ведет себя отличным, когда это первая вставка, а когда нет
- Test 1) перед постановкой работает в два раза для первого введения, но только один раз после того, что
ДО ЗАЯВЛЕНИЕ IS Кол-во: 0 ДО ВЫСТУПЛЕНИЯ IS Кол-во: 0
- Тест 2) Значение переменной имеет значение NULL для первой вставки и ожидаемое значение после этого.
ПОСЛЕ ВЫСТУПЛЕНИЯ IS Кол-во:
Можете ли вы объяснить такое поведение?
SET SERVEROUTPUT ON;
--DROP TABLE teste_var_global;
CREATE TABLE teste_var_global(
idVal NUMBER
);
create or replace TRIGGER compounder
FOR UPDATE OR INSERT OR DELETE ON teste_var_global
COMPOUND TRIGGER
qty NUMBER;
BEFORE STATEMENT IS
BEGIN
SELECT COUNT(*) INTO qty FROM teste_var_global;
DBMS_OUTPUT.PUT_LINE('BEFORE STATEMENT IS');
DBMS_OUTPUT.PUT_LINE('Qty: ' || qty);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('(' || SQLCODE || ') - ' || SQLERRM);
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
DBMS_OUTPUT.PUT_LINE(CHR(9)||'BEFORE EACH ROW IS');
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE(CHR(9)||':new.idVal ' || :new.idVal);
ELSIF DELETING THEN
DBMS_OUTPUT.PUT_LINE(CHR(9)||':old.idVal ' || :old.idVal);
ELSE --UPDATING
DBMS_OUTPUT.PUT_LINE(CHR(9)||':old.idVal ' || :old.idVal);
DBMS_OUTPUT.PUT_LINE(CHR(9)||':new.idVal ' || :new.idVal);
END IF;
END BEFORE EACH ROW;
AFTER EACH ROW IS
BEGIN
DBMS_OUTPUT.PUT_LINE(CHR(9)||'AFTER EACH ROW IS');
IF INSERTING THEN
DBMS_OUTPUT.PUT_LINE(CHR(9)||':new.idVal ' || :new.idVal);
DBMS_OUTPUT.NEW_LINE();
qty:= qty + 1; -- increment
ELSIF DELETING THEN
DBMS_OUTPUT.PUT_LINE(CHR(9)||':old.idVal ' || :old.idVal);
DBMS_OUTPUT.NEW_LINE();
qty:= qty -1; -- decrement
ELSE --UPDATING
DBMS_OUTPUT.PUT_LINE(CHR(9)||':old.idVal ' || :old.idVal);
DBMS_OUTPUT.PUT_LINE(CHR(9)||':new.idVal ' || :new.idVal);
DBMS_OUTPUT.NEW_LINE();
END IF;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
DBMS_OUTPUT.PUT_LINE('AFTER STATEMENT IS');
DBMS_OUTPUT.PUT_LINE('Qty: ' || qty);
DBMS_OUTPUT.NEW_LINE();
END AFTER STATEMENT;
END;
/
-- Test 1, will fire BEFORE STATMENT twice when the first row is inserted
INSERT INTO teste_var_global
(
SELECT 1 FROM DUAL
UNION ALL
SELECT 2 FROM DUAL
UNION ALL
SELECT 3 FROM DUAL
)
/
--Test 2, qty will become NULL when this trigger is fired for the first time
--drop the table and rerun the trigger before executing this command
INSERT INTO teste_var_global VALUES(1);
/
Потому что Oracle гарантирует, что триггер будет запущен ** в последний раз **, но не гарантирует, что он запущен ** ровно один раз ** в многопользовательской среде, см. Эту ссылку: https://asktom.oracle .com/pls/asktom/f? p = 100: 11: 0 :::: P11_QUESTION_ID: 2599480800346313755 – krokodilko
@krokodilko Это очень хорошее объяснение. – Kacper