PL / SQL: запустить пакет после проверки всех строк в триггере - PullRequest
0 голосов
/ 14 февраля 2020

У меня есть таблица инвентаризации с ожидаемыми и фактически полученными количествами. Допустим, inv.q_ex и inv.q_rd.

ВСТАВКА в таблицу имеет положительное значение в q_ex и ноль в q_rd, потому что он еще не прибыл. Я хотел бы запустить пакет, когда обнаружу, что значение q_rd изменяется с 0 на что-то другое, указывая, что оно получено и сохранено.

Создание триггера для обнаружения после обновления и проверки каждой строки легко, но Я не уверен, как обеспечить его запуск только один раз.

Скелет:

CREATE OR REPLACE TRIGGER example
     AFTER UPDATE ON inv
          FOR EACH ROW
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         pkg.proc();
                    END IF;
               END;
/

Проблема, которую я вижу, заключается в том, что я хочу, чтобы она запускалась только один раз. Мне просто нужно определить, когда это должно быть выполнено. В идеале, в первом ряду, где выполняется мое условие, я должен был выйти из l oop (кажется, что тратить время на проверку, когда я уже знаю, что мне нужно выполнить) и вызвать мою процедуру.

Я не мог Не могу найти способ «выйти» для каждого и обработать его как обычное ПОСЛЕ ОБНОВЛЕНИЯ, поэтому я попытался использовать как ДО ОБНОВЛЕНИЯ, так и ПОСЛЕ ОБНОВЛЕНИЯ. Часть BEFORE будет проверять каждую строку и обновлять логическое значение. Часть AFTER будет ждать, пока это произойдет, и, если это так, вызовите процедуру.

CREATE OR REPLACE TRIGGER example
     BEFORE UPDATE ON inv
          FOR EACH ROW
               DECLARE
                    shouldExecute BOOLEAN;
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         shouldExecute := TRUE;
                    END IF;
               END;
     AFTER UPDATE ON inv
          BEGIN
               IF shouldExecute THEN
                    pkg.proc();
               END IF;
          END;
/

Я подозреваю, что это не сработает в любом случае, потому что, согласно синтаксису, она повторно объявляет логическую переменную на каждом строка. Я подумал, что, возможно, я смогу сделать его «глобальным», но, как бы то ни было, оказалось, что я не могу добавить и ДО, и ПОСЛЕ к одному и тому же триггеру по какой-то причине (если я недостаточно исследовал), поэтому я разбил его на два триггера. , Проблема в том, что я не могу разделить это логическое значение между двумя триггерами. Могу ли я поделиться значением или я все об этом ошибаюсь?

Ответы [ 2 ]

0 голосов
/ 16 февраля 2020

Вы должны сделать больше исследований. По ссылке выше вы можете начать обсуждение для Oracle 9. Я надеюсь, что вы на самом деле не используете эту версию; поддержка завершилась в 2007 году. Начиная с версии 11g Oracle предусмотрены «составные триггеры», в которых можно запускать один и тот же триггер как до, так и после, как для оператора, так и для уровня строки. Составные триггеры позволяют совместно использовать переменные между различными вызовами.

0 голосов
/ 15 февраля 2020

Здесь много маленьких вопросов, поэтому я постараюсь ответить на них все:)

Относительно "FOR EACH ROW", Oracle триггеры поддерживают два различных метода запуска, STATEMENT или ROW. Если вы включите «FOR EACH ROW» в определение, вы получите триггер строки, который запускается один раз для каждой строки, затронутой запросом, что, как вам кажется, здесь и нужно. Триггеры уровня оператора срабатывают только один раз для каждого запроса. Преимущество использования триггеров строк заключается в том, что вы можете использовать метавария: OLD и: NEW, которые ссылаются на предыдущее и текущее значения строки.

Как вы обнаружили, вы не можете добавлять BEFORE и AFTER к тот же триггер - вам нужно разбить их на два триггера.

К сожалению, не существует простого способа разделения логической переменной между двумя триггерами. Возможно, самый простой способ - создать пакет с переменной publi c, которую можно установить в триггере BEFORE, и проверить в триггере AFTER.

Пакет будет выглядеть примерно так:

CREATE OR REPLACE PACKAGE PCKG_DEMO
AS
  shouldExecute BOOLEAN;
END;
/

Тогда ваш триггер BEFORE UPDATE:

CREATE OR REPLACE TRIGGER beforeexample
     BEFORE UPDATE ON inv
          FOR EACH ROW
               BEGIN
                    IF :OLD.q_rd = 0 AND :NEW.q_rd > 0 THEN
                         PCKG_DEMO.shouldExecute := TRUE;
                    END IF;
               END;
/

И ваш триггер AFTER UPDATE:

CREATE OR REPLACE TRIGGER afterexample
     AFTER UPDATE ON inv
        FOR EACH ROW
          BEGIN
               IF PCKG_DEMO.shouldExecute THEN
                    pkg.proc();
               END IF;
          END;
/

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

...