#sql #plsql #triggers #oracle-apex
#sql #plsql #триггеры #oracle-apex
Вопрос:
Я пытаюсь создать триггер для проверки, содержит ли новая запись в таблице registraties
(регистрации) действительный MNR (номер сотрудника), но я застрял в той части, где я ссылаюсь на таблицу medewerkers
(сотрудники).
Может ли кто-нибудь мне помочь?
CREATE OR REPLACE TRIGGER t_MNRcontrole
BEFORE INSERT OR UPDATE
ON registraties
DECLARE
MNR_medewerkers number (SELECT MNR FROM MEDEWERKERS);
FOR EACH ROW
BEGIN
IF :new.MNR <> MNR_medewerkers
THEN raise_application_error(-20111, 'Medewerker niet herkend!');
END IF;
END;
Полученное сообщение об ошибке
ORA-24344: success with compilation error
Ответ №1:
Оператор присваивания PL / SQL — это :=
или select x into y from z
для заполнения из SQL-запроса.
FOR EACH ROW
является частью спецификации триггера, а не кода PL / SQL.
Если :new.mnr
отсутствует в родительской таблице, вы получите no_data_found
исключение, а не несоответствующую переменную.
Рекомендуется, чтобы сообщения об ошибках включали подробную информацию о сбое.
В программировании мы используем отступ для обозначения структуры кода.
Фиксированная версия будет выглядеть примерно так:
create or replace trigger trg_mnrcontrole
before insert or update on registraties
for each row
declare
mnr_medewerkers medewerkers.mnr%type;
begin
select mw.mnr into mnr_medewerkers
from medewerkers mw
where mw.mnr = :new.mnr;
exception
when no_data_found then
raise_application_error(-20111, 'Medewerker '||:new.mnr||' niet herkend!');
end;
Однако мы можем лучше реализовать этот вид проверки, используя ограничение внешнего ключа, например:
alter table registraties add constraint registraties_mw_fk
foreign key (mnr) references medewerkers.mnr;
Комментарии:
1. Спасибо! Я добавил код ошибки, и я на самом деле не уверен, как сделать отступ, попробовал
TAB
, но, похоже, это не сработало. Только что нашел сайт, на котором говорится, что его можно изменить в настройках, поэтому я попробую это немного. Я думаю, что ваше решение должно работать, я не привык к этимSELECT INTO
заявлениям. Я все еще знакомлюсь с возможностями. Большое спасибо за ваше объяснение.2. Триггер — не лучший способ решить эту проблему — для этой цели существуют ограничения внешнего ключа. Вместо этого взгляните на это
3. Я не знаю, какой редактор вы используете, но я нахожу, что 4 пробела выполняют эту работу 🙂
Ответ №2:
Номер MNR_medewerkers (ВЫБЕРИТЕ MNR ИЗ MEDEWERKERS);
всегда будет сбой, потому что это не ЧИСЛО, если только в вашей таблице не будет только одной единственной записи, и даже тогда я не уверен, что PLSQL позволит ей пройти.
Более стандартным вариантом для этого было бы сначала объявить число, затем в codeblock вы выполняете SELECT INTO вместе с предложением WHERE, где вы убедитесь, что выбрали только одну конкретную строку из таблицы. Затем вы можете сравнить это число с новым.
Если, однако, вы не пытаетесь сравнивать с одной конкретной строкой, а вместо этого проверяете, существует ли запись в этой таблице.
BEGIN
SELECT 1
INTO m_variable
FROM table
WHERE MNR = :new.MNR;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
m_variable = 1;
WHEN OTHERS THEN
m_variable = 0;
END;
Заранее объявите переменную m_variable, а затем проверьте, соответствует ли она 0, а затем сообщите об ошибке.
Значение too_many_rows используется в случае, если в таблице с этим MNR имеется более одной строки, а ОСТАЛЬНЫЕ — для NO_DATA_FOUND, но я использую ДРУГИЕ для обработки всего остального, что может произойти, но, вероятно, не будет.
Кстати, это блок кода, который должен быть включен в основной блок кода, поэтому между вашими BEGIN и IF просто измените IF, чтобы проверить, равна ли переменная 0.
Комментарии:
1. Я чувствую, что ваш ответ должен сработать, однако я не могу заставить его работать. Чтобы уточнить, MNR — это PK в
medewerkers
, и я хочу проверить, известен ли сотрудник (MNR) при попытке регистрации (вставить строку в таблицуregistraties
). Если нет, показать ошибку.