Как исправить базовый триггер, не срабатывающий в SQL Oracle

Я пытался заставить этот триггер работать, но по какой-то причине он даже не активируется до того, как я обновлю/вставлю данные в таблицу. Цель этого триггера (и я должен сделать это с помощью триггеров) — гарантировать, что все записи в таблице DISCS имеют либо «L», либо «S» в атрибуте FORMAT. Если нет, запись не должна быть вставлена/обновлена.

Я попытался добавить строку, чтобы проверить, активировался ли триггер вообще (строка «buenos dias»), но, похоже, это не по какой-то причине. Я просто новичок в триггерах, и я уверен, что ошибка действительно глупая, но я просто не могу ее найти.

Код для триггера:

CREATE OR REPLACE TRIGGER FORMAT_T
  BEFORE INSERT OR UPDATE OF FORMAT
  ON DISCS
  FOR EACH ROW
DECLARE
  bad_format EXCEPTION;
BEGIN
  DBMS_OUTPUT.PUT_LINE('Buenos dias.');
  IF :NEW.FORMAT != 'S' AND :NEW.FORMAT != 'L' THEN
    RAISE bad_format;
  END IF;
EXCEPTION
  WHEN bad_format THEN
    DBMS_OUTPUT.PUT_LINE('Bad format, could not insert/update.');
END FORMAT_T;

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

UPDATE DISCS
SET FORMAT = 'W'
WHERE ID = 1;

Это должно возвращать ошибку, поскольку формат, который я обновляю, не является «L» или «S», но вместо этого строка просто обновляется без проблем и даже без появления строки «buenos dias». В таблице user_errors ошибок тоже нет.

Спасибо за вашу помощь заранее.

Сообщение отладки не остановит ввод значения. Вероятно, это должно вызвать исключение.

William Robertson 21.04.2019 15:51

@WilliamRobertson что остановит ввод значения, так это исключение «bad_format», а не сообщение отладки. Технически это исключение предотвратит его ввод

alestarbucks 21.04.2019 16:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
655
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ваша проблема связана с

IF :NEW.FORMAT != 'S' AND :NEW.FORMAT != 'L' THEN

утверждение

Просто замените на

IF :NEW.FORMAT not in ('S','L') THEN

но я бы предпочел использовать контрольное ограничение:

ALTER TABLE discs
ADD CONSTRAINT chk_format CHECK (format in ('S','L'))

В этом случае база данных автоматически выдает "проверочное ограничение нарушено" при вводе символов, отличных от 'S' или 'L', без необходимости запуска.

Я использовал AND, так как условие возбуждения исключения состоит в том, что формат не соответствует ни S, ни L, то есть выполняются оба неравенства. Если я использую OR, триггер ВСЕГДА будет генерировать исключение. Дело в том, что триггер даже не срабатывает (строка "buenos dias" не печатается). Я пытался внести эти изменения, но триггер в любом случае ничего не делает. Кроме того, по заданию я должен делать это с помощью триггеров, поэтому я не могу использовать ограничения.

alestarbucks 21.04.2019 12:26

@alestarbucks нет, :NEW.FORMAT != 'S' OR :NEW.FORMAT != 'L' равно NOT(:NEW.FORMAT = 'S' AND :NEW.FORMAT = 'L'), как в символической логике, или общий множитель для сложения/вычитания в математике.

Barbaros Özhan 21.04.2019 12:30

хорошо, спасибо за это, я обновлю эту часть кода. Однако триггер по-прежнему не срабатывает: тестовая строка не выскакивает и строка обновляется без проблем, не показывая исключение.

alestarbucks 21.04.2019 12:33

@alestarbucks Хорошо, отредактировано. Использование not in понятнее.

Barbaros Özhan 21.04.2019 12:41
Ответ принят как подходящий

Ваш код триггера в том виде, в котором он опубликован, работает нормально. Настоящая проблема раскрывается следующим образом:

without the "buenos dias" line even popping up

Очевидно, вы работаете в среде, в которой DBMS_OUTPUT отключен. Таким образом, ОБНОВЛЕНИЕ не выполняется, как и ожидалось, вы просто не видите сообщения. Мы можем легко продемонстрировать это, удалив блок EXCEPTION из кода триггера, как этот Скрипт SQL демонстрирует.

Включение DBMS_OUTPUT зависит от вашей среды выполнения. В SQL*Plus запустите set serveroutput on. В Oracle SQL Developer выберите View > Dbms_Output и установите соединение. В PL/SQL Developer включите DBMS_OUTPUT на листе SQL. И так далее.


Между прочим, триггер — неправильный способ применить это правило. Правильный подход — определить проверочное ограничение для столбца.

alter table disks add constraint disc_format_ck 
    check (format in ('S', 'L'));
CREATE OR REPLACE TRIGGER FORMAT_T
BEFORE INSERT OR UPDATE
OF FORMAT
ON DISCS
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN 
  IF :NEW.FORMAT not in( 'S' , 'L') THEN    
    raise_application_error(-20010,'Bad format, could not insert/update.');
  END IF;   
EXCEPTION
  WHEN OTHERS THEN    
    DBMS_OUTPUT.PUT_LINE('OTHERS EXCEPTION');   
END FORMAT_T;

ИСПОЛЬЗУЙТЕ повышение_приложения_ошибка:

поднять_приложение_ошибка(-20010,'Неверный формат, не удалось вставить/обновить.');

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