Tylko dlatego, że masz zamiar zobaczyć to niepowodzenie i nie odbierać niczego od punktów APC, wydaje się, że działa to na pierwszy rzut oka, o ile jest to before
wyzwalacz:
create table t42 (id number);
create trigger trig42
before insert or update on t42
for each row
declare
c number;
begin
if :new.id is null then
raise_application_error(-20001, 'ID is null');
end if;
select count(*) into c from t42 where id = :new.id;
if c > 0 then
raise_application_error(-20002, 'ID is not unique');
end if;
end;
/
Kompiluje się i jeśli wstawisz dane, uzyskasz pożądane zachowanie:
insert into t42 values (1);
1 rows inserted.
insert into t42 values (1);
Error starting at line 20 in command:
insert into t42 values (1)
Error report:
SQL Error: ORA-20002: ID is not unique
ORA-06512: at "STACKOVERFLOW.TRIG42", line 9
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'
insert into t42 values (null);
Error starting at line 22 in command:
insert into t42 values (null)
Error report:
SQL Error: ORA-20001: ID is null
ORA-06512: at "STACKOVERFLOW.TRIG42", line 5
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'
select * from t42;
ID
----------
1
Który wydaje się robić to, czego chcesz. Ale nie, jeśli masz więcej niż jedną sesję. Nie popełniłem w tej sesji; w innej sesji mogę zrobić:
insert into t42 values (1);
1 row created.
select * from t42;
ID
----------
1
1 row selected.
Hmm, to dziwne. Cóż, może to odroczone... popełnijmy je obie:
commit;
select * from t42;
ID
----------
1
1
2 rows selected.
Ups. Jedna sesja nie może zobaczyć niezatwierdzonych danych innej sesji, więc to nigdy nie zadziała.
Również problem z tabelą mutacji ujawnia się, gdy wstawiamy wiele wierszy w jednej instrukcji:
SQL> insert into t42 select level+1 from dual connect by level <= 5;
insert into t42 select level+1 from dual connect by level <= 5
*
ERROR at line 1:
ORA-04091: table STACKOVERFLOW.T42 is mutating, trigger/function may not see it
ORA-06512: at "STACKOVERFLOW.TRIG42", line 7
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'
SQL>
Podwójne ups.
Nawet z after
wyzwalacz i pakiet do obejścia problemu z tabelą mutacji, nadal będziesz miał ten problem (chyba), chyba że zablokujesz całą tabelę dla każdej wstawki lub aktualizacji. Jak powiedział APC, ograniczenie jest zaimplementowane głęboko w trzewiach bazy danych, a nie na tym poziomie.
Nie, kiedy masz więcej niż jedną sesję, nie. Nawet w ciągu jednej sesji, jeśli nie masz indeksu w kolumnie, wydajność nie będzie skalowana jako count(*)
będzie coraz wolniej. A jeśli masz indeks, cóż, dlaczego nie uczynić go unikalnym indeksem?
Na koniec z wytycznych dotyczących projektowania wyzwalaczy :