2014-01-21 3 views
0

У меня есть небольшой столик, глядя, как этотTrigger избежать мутирует таблицы и обновление: new.values ​​

table People 
( name VARCHAR(20) PRIMARY KEY 
    ,group NUMBER(4) 
); 

И мне нужно, чтобы создать триггер (или триггеры) Thats позволит ниже правила работы:
- 1 если есть более 10 имена в группе Мне нужно поднять сообщение об ошибке, если кто-то пытается ВСТАВИТЬ следующих людей для этой группы.
- 2, если ВСТАВИТЬ приходит со значением NULL для группы поля мне нужно назначить его группу, которая меньше количества затем 10.
- 3, если есть 10 имен во всех группах я необходимо сгенерировать следующими группа номер.
- 4 Мне нужно избегать мутирующий стол ошибка.

Это то, что я сделал до сих пор:

CREATE OR REPLACE TRIGGER people_bis 
BEFORE INSERT ON people 
FOR EACH ROW 
DECLARE 
PRAGMA AUTONOMOUS_TRANSACTION; 
g_count NUMBER(4); 
g_num NUMBER(4); 
g_l NUMBER(4); 
g_r NUMBER(4); 

BEGIN 

Select count(*) into g_count from people where group = :new.group; 
If g_count > 9 Then 
raise_application_error (-20003,'Group reached it limit, please choose other'); 
End if; 
If :NEW.group = '' or :NEW.group is null Then 
select count (*) into g_l from (select count(imie),group from people group by group having count(name) = 10); 
select count (distinct group) into g_r from people; 
    if g_l = g_r then 
    select max(group)+1 into g_num from people; 
    else 
    select group into g_num from(select group, count(name) from people having count(name) < 10 group by group order by count(group) desc) where rownum < 2; 
    End if; 
:New.group := g_num; 
End if; 
End people_bis; 

Код выше работ, но когда я вставляю, как выбрать из таблицы зеркала, например,
INSERT INTO people(name) select concat(name,'_next') from people_mirror; В результате оно превышает заданный предел (10) для группы. Также я знаю, что использование PRAGMA AUTONOMOUS_TRANSACTION не лучший способ избежать ошибки в изменении таблицы, и я знаю, что могу достичь этой функциональности, если бы я разделил триггер строки в триггеры операторов, но я просто не понимаю, как это получить ,

Так кто-нибудь? ;)

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

------------------- EDIT ------------------------

Это триггеры, которые работают, но все же у меня есть сомнения относительно них, поскольку оба они являются ПЕРЕД и строковыми типами.

CREATE OR REPLACE TRIGGER people_bir1 
BEFORE INSERT on people 
FOR EACH ROW 
DECLARE 
V_count NUMBER(2); 
BEGIN 
    If :NEW.group = '' or :NEW.group is null then 
    return; 
    end if; 
insert into groups values(:New.group,1); 
exception when dup_val_on_index then 
Select count into v_count from groups where group = :New.group; 
UPDATE groups set count = v_count+1 where group = :New.group; 

END people_bir1;  

CREATE OR REPLACE TRIGGER people_bir2 
BEFORE INSERT on people 
FOR EACH ROW 
DECLARE 
g_count NUMBER(2); 
g_num NUMBER(2); 
begin 
    if :NEW.group = '' or :NEW.group is null Then 
    select min(count) into g_count from groups; 
     if g_count = 10 Then 
     select max(group) into g_num from groups; 
     g_num := g_num+1; 
     Else 
     select min(group) into g_num from group where count = g_count; 
     End if; 
    :New.group := g_num; 
    Else 
    select count into g_count from groups where group=:New.group; 
    if g_count > 9 then 
    raise_application_error (-20003,'More then 10 people in group please select another'); 
    end if; 
    end if; 
end people_bir2; 

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

ответ

2

Вы правы, что добавление PRAGMA AUTONOMOUS_TRANSACTION не является решением проблемы.Один из способов сделать это, чтобы сохранить количество людей в группе в GROUPS таблице (если вы не имеете GROUPS таблицу, то вы можете добавить один), используя триггеры НАРОДА:

  • После ВСТАВКА на людей: обновление гРУППА, добавить-сосчитать группы они находятся в
  • После удаления на людях: обновление гРУПП вычитать 1 из графа группы они находятся в
  • После обновления на людях: обновление группы, добавить 1 к новой группе, вычитать 1 от старой группы

Тогда ваш ПЕРЕД НАЧАЛОМ SERT триггер не нужно смотреть на стол людей, он может смотреть на группы:

Select people_count into g_count from groups where group = :new.group 
for update; 

Обратите внимание на оговорку for update, чтобы заблокировать GROUPS строку, пока транзакция не будет завершена.

+0

Так что я смог разбить его на два триггера, используя дополнительную таблицу 'группы таблиц (группа NUMBER (4) PRIMARY KEY, count NUMBER (2)' и два триггера, но оба они до триггеров строк. работает, но у меня есть сомнения, что использование двух перед триггерами - это правильное решение. Я присоединяю их как ответ ниже. Пожалуйста, взгляните, можете ли вы, чтобы исправить меня. – plomien

+0

новая версия включена в вопрос под маркой EDIT. – plomien

0

Вы можете использовать спусковой механизм. Это выглядит следующим образом:

CREATE OR REPLACE TRIGGER people_bis 
    FOR INSERT ON people 
COMPOUND TRIGGER 

g_count NUMBER(4); 
g_num NUMBER(4); 
g_l NUMBER(4); 
g_r NUMBER(4); 

BEFORE STATEMENT IS 
BEGIN 

    Select count(*) into g_count from people where group = :new.group; 
    If g_count > 9 Then 
    raise_application_error (-20003,'Group reached it limit, please choose other'); 
    End if; 

    select count (*) into g_l from (select count(imie),group from people group by group  having count(name) = 10); 
    select count (distinct group) into g_r from people; 

    if g_l = g_r then 
    select max(group)+1 into g_num from people; 
    else 
    select group into g_num from(select group, count(name) from people having count(name) < 10 group by group order by count(group) desc) where rownum < 2; 
    End if; 

END BEFORE STATEMENT; 

BEFORE EACH ROW IS 
BEGIN 

    If :NEW.group = '' or :NEW.group is null Then 
    :New.group := g_num; 
    End if; 
END BEFORE EACH ROW; 

End people_bis; 

Пожалуйста, обратите внимание, что, скорее всего, этот код не работает, как вы хотите, но это должно дать вам общее представление, как работать с соединением Trigger.

+0

Thank вы за свой совет, но я не упомянул, что для этой задачи я не могу использовать триггеры compoud: / – plomien