Plsql: Как написать этот триггер, используя триггер уровня оператора? - PullRequest
0 голосов
/ 05 апреля 2019

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

Вот вопрос:

Реализация и всесторонняя проверка триггера оператора, который проверяет Следующее ограничение согласованности.

«Позиция не может требовать более 4 навыков».

Когда все будет готово, сохраните оператор CREATE TRIGGER и все операторы SQL, которые всесторонне протестировать триггер в скрипте solution3.sql. Комплексное тестирование означает, что триггер должен отклонять операторы SQL, которые нарушают ограничение согласованности, и принимать операторы SQL, которые не нарушают ограничение согласованности. Это часть вашей задачи, чтобы найти, какие операторы SQL должны быть проверены. Всякий раз, когда оператор SQL нарушает ограничение согласованности, триггер должен возвращать сообщение об ошибке ORA-…. Используйте процедуру RAISE_APPLICATION_ERROR для возврата сообщения об ошибке ORA-…. Если оператор SQL не нарушает ограничение согласованности, триггер должен вернуть no Сообщения.

Вот файлы базы данных, если вы хотите попробовать эту проблему: https://www.dropbox.com/sh/4dyemye2bpq5hv4/AAAEAmTDELHcgFFhpfRrqHtDa?dl=0

Код, который я написал, дает мне ошибку, что новое и старое не могут использоваться в триггерах уровня таблицы, и я думаю, что эта функция будет работать, если я сделаю это триггером уровня строки, но мне нужно, чтобы он работал как триггер оператора. Подскажите, пожалуйста, что я делаю не так.

create or replace trigger checkskillnum
before insert or update of pnumber on sneeded
declare
skillnum number;
begin
select count(*) into skillnum from sneeded where sneeded.pnumber = :new.pnumber;
if skillnum > 3 then
RAISE_APPLICATION_ERROR(-20030,'A position does not need more than 4 skills');
end if;
end;
/

Результат должен позволять вставлять или обновлять только те операторы, где skillnum меньше 4. Но сейчас это соответствует ошибке: новое и старое нельзя использовать для триггеров на уровне таблицы.

НОВОЕ РЕШЕНИЕ:

Таблица SNEEDED: Оператор select имеет первый результат, равный 4, и триггер только проверяет этот результат, даже если значение pnumber отличается.

SQL> select pnumber, count(*) as SKILL_COUNT
  2                   from sneeded
  3                   group by pnumber
  4                   order by COUNT(*) DESC
  5  ;

   PNUMBER SKILL_COUNT
---------- -----------
         1           4
         2           3
         3           3
         7           3
         5           3
         6           1
         4           1

7 rows selected.

Ошибка в новом решении:

SQL> insert into sneeded values(1,'fishing',7);
insert into sneeded values(1,'fishing',7)
            *
ERROR at line 1:
ORA-20030: A position does not need more than 4 skills
ORA-06512: at "SYSTEM.CHECKSKILLNUM", line 8
ORA-04088: error during execution of trigger 'SYSTEM.CHECKSKILLNUM'


SQL> insert into sneeded values(2,'fishing',7);
insert into sneeded values(2,'fishing',7)
            *
ERROR at line 1:
ORA-20030: A position does not need more than 4 skills
ORA-06512: at "SYSTEM.CHECKSKILLNUM", line 8
ORA-04088: error during execution of trigger 'SYSTEM.CHECKSKILLNUM'


SQL> insert into sneeded values(4,'fishing',7);
insert into sneeded values(4,'fishing',7)
            *
ERROR at line 1:
ORA-20030: A position does not need more than 4 skills
ORA-06512: at "SYSTEM.CHECKSKILLNUM", line 8
ORA-04088: error during execution of trigger 'SYSTEM.CHECKSKILLNUM'

1 Ответ

0 голосов
/ 05 апреля 2019

Триггер оператора (который не имеет FOR EACH ROW) не может использовать :OLD и :NEW, потому что у него нет доступа к значениям строки. Но в этом случае они вам на самом деле не нужны - вам просто нужно думать по-другому.

Что вас волнует, так это то, что после выполнения оператора есть люди с более чем тремя навыками? Поэтому вам нужно выяснить, как найти этот бит информации.

Следующее должно сделать это для вас:

create or replace trigger checkskillnum
  before insert or update on sneeded
begin
  FOR aRow IN (select pnumber, count(*) as SKILL_COUNT
                 from sneeded 
                 group by pnumber
                 order by COUNT(*) DESC)
  LOOP
    IF aRow.SKILL_COUNT > 3 THEN
      RAISE_APPLICATION_ERROR(-20030, 'A position does not need more than 4 skills');
    END IF;

    EXIT;    -- The first row will have the highest SKILL_COUNT, so only need to  
  END LOOP;  -- check the first row.
end CHECKSKILLNUM;

Удачи.

...