Как создать триггер, который должен проверить, находится ли новое значение в массиве в той же таблице (оракул 11g) - PullRequest
0 голосов
/ 01 мая 2018

У меня есть стол и доктор. У доктора есть множество специальностей и ссылка на область, в которой он работает. Триггер, который я пытаюсь создать, проверяет, совпадает ли имя области, на которую я буду ссылаться в обновлении, с именем одного из его специальностей.

Я пробовал разные вещи, но ни одна из работ

Пример 1.

CREATE OR REPLACE TRIGGER TRIGGER9 
BEFORE INSERT ON DOCTOR 
FOR EACH ROW
WHEN (deref(new.worksIn).name in (select m.COLUMN_VALUE.name from table (select deref(specialities) from doctor where pid = new.pid)
BEGIN
   null;
END;

Пример 2.

CREATE OR REPLACE TRIGGER TRIGGER9
BEFORE INSERT ON DOCTOR
FOR EACH ROW
BEGIN
    if deref(:new.worksIn).name in (select deref(:new.specialities).name) then
       -- stuff happens
    end if
END;

Заранее спасибо!

1 Ответ

0 голосов
/ 01 мая 2018

Мы не можем создавать ограничения на типы объектов. Это только одна из причин, почему использование типов объектов для сохранения (а не в программах на PL / SQL) не рекомендуется.

Однако можно обеспечить уникальность в триггере. Этот создает набор записей (то есть один экземпляр уникальных значений) и сравнивает его с фактической вложенной таблицей. Если число отличается, то у вложенной таблицы есть повторяющиеся значения.

Настройка:

create or replace type speciality_t as object (name varchar2(30));
/

create or replace type specialities_nt as table of speciality_t;
/

create table doctors (
     doctor_id number primary key
     , works_in specialities_nt
     )
nested table works_in store as works_in_nt     ;

Триггер:

create or replace trigger ck_speciality 
    before insert or update on doctors
    for each row
declare
    dummy1 specialities_nt;
    dummy2 number;
begin
    -- all the unique values for WORKS_IN
    select  set(:new.works_in)
    into dummy1
    from dual;

    -- count diff 
    select  m - n
    into dummy2
    from ( select count(*) as m from table(:new.works_in)) t1
        cross join  ( select count(*) as n from table(dummy1)) t2;

    -- hurl if the difference is not zero
    if dummy2 != 0 then
        raise_application_error (-20042, 'duplicate speciality'); 
    end if;
end;
/

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

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

...