возрастной контроль 2 для пл / кв. - PullRequest
0 голосов
/ 23 марта 2020

Я пытаюсь выяснить, в каком возрасте начал работать сотрудник. если ему исполнилось 16 лет, он должен сообщить об ошибке «Ошибка при вводе даты рождения». так что мой триггер создан, но мой триггер не работает, я получаю эту ошибку: ORA-01422: Точный поиск возвращает больше, чем запрошенное количество строк

я не могу найти проблему Вот код:

SET SERVEROUTPUT ON
ACCEPT Birthday PROMPT ' Pleas give you Date of birth: ' 
CREATE OR REPLACE TRIGGER T_Controll
before INSERT ON  meine_Firma -- Table
FOR EACH ROW
DECLARE
V_Berufstart            meine_Firma.Hiredate%TYPE; --Job begin
V_Geburtsdatum          DATE; -- Date of birth
V_Alter                 number:=0; -- AGE
SELECT HIREDATE INTO V_Berufstart FROM meine_Firma;
BEGIN
V_Geburtsdatum:=('&Birthday');  
V_Alter:= Round(MONTHS_BETWEEN(V_Berufstart,V_Geburtsdatum)-2)/12;
IF 16 > V_Alter THEN   
RAISE_APPLICATION_ERROR(-20201,'Error when entering the date of birth');
END IF;
END;
/

SET SERVEROUTPUT OFF

Если ему меньше 16 лет, он может не работать, извините, мой английский sh не хорош (=

Ответы [ 2 ]

2 голосов
/ 24 марта 2020

В этом скрипте гораздо более серьезная проблема, чем ошибка, которую вы получаете. Даже после исправления, предложенного @ShaunPeterson, он все равно не будет работать, он НЕ БУДЕТ выдавать ошибку, он просто не будет работать так, как вы ожидаете. Проблема в том, что вы не поняли переменные подстановки - использование & name (в частности, здесь & Birthday.) Я буду использовать & Birthday в следующем, но обсуждение относится к ЛЮБЫМ / ВСЕМ переменным подстановки.

люди не понимают, почему они не могут использовать переменные подстановки "&" в своих процедурах и функциях PL / SQL для запроса ввода во время выполнения. Надеемся, что эта статья поможет вам прояснить, в чем заключаются различия, чтобы вы могли понять, где и когда их использовать.

  1. Переменные подстановки Подсказка здесь в названии ... "подстановка". Это относится к значениям, подставляемым в код перед его отправкой в ​​базу данных. Эти замены выполняются используемым интерфейсом

Эффект этой замены заключается в том, что строка , содержащая переменную подстановки, физически переписывается интерфейсом, заменяющим% Birthday , В этом случае, если вы не введете значение или дату 2000-05-19, оператор до и после подстановки будет

  • ДО: V_Geburtsdatum: = ('& Birthday');
  • ПОСЛЕ: V_Geburtsdatum: = (''); ИЛИ V_Geburtsdatum: = ('2000-05-19');

В любом случае после того, что видит компилятор после; он вообще не видит% Birthday. Более того, при запуске триггер не будет запрашивать значение. Что касается компилятора, это жестко закодированное значение, которое никогда не изменится. Помимо этого, триггер или любой другой сценарий PL SQL (сохраненный или анонимный) никогда не запрашивает значения , они фактически не способны сделать это, поскольку это не является частью языка. Любая подсказка через ваш интерфейс программного обеспечения не PL sql.

Я собираюсь предложить способ вообще избежать триггера. Начало работы soap box: Триггеры ПЛОХО, они полезны для назначения ключей автоматического увеличения (до 12 c), ведения журнала, очень ограниченного аудита и т. Д. c. Однако для бизнес-правил они должны быть последним средством. Ok Выйти из soap коробки.

Прежде всего, чтобы столбцы meine_Firma.Hiredate и meine_Firma.Geburtsdatum НЕ были равны нулю (если это еще не сделано). Если любой из них равен NULL, вы не можете ничего с ним вычислить, результатом будет NULL. Во-вторых, создайте новый столбец age_at_hire (или любой другой) в качестве виртуального столбца, затем установите для него ограничение проверки. И вуаля триггер больше не нужен. См. fiddle для демонстрации.
Итак, предлагаемое изменение (ДА, вам, вероятно, придется сначала очистить плохие данные):

alter table meine_Firma modify 
          ( hiredate     not null
          , Geburtsdatum not null
          ) ;
alter table meine_Firma add                           
          ( age_at_hire integer generated always as (trunc(months_between(hiredate,Geburtsdatum))) virtual
          , constraint check_age_at_hire check (age_at_hire >= 16*12)
          );

В любом случае, я надеюсь, что вы получите понимание переменных подстановки на будущее. И учитесь избегать триггеров. Удачи.

1 голос
/ 23 марта 2020

Причина, по которой вы получаете указанную ошибку c, заключается в том, что при выборе ниже будет выбрано ВСЕ строки из meine_Firma, так как нет условия where

SELECT HIREDATE INTO V_Berufstart FROM meine_Firma;

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

V_Berufstart := :NEW.HIREDATE;

Если бы это был триггер обновления, была бы объявлена ​​переменная связывания: NEW и: OLD, чтобы вы могли получить доступ к значениям OLD и NEW. Поскольку это триггер вставки, то: OLD будет просто нулевым, поскольку старых значений нет.

...