Oracle
 sql >> Baza danych >  >> RDS >> Oracle

jak zrobić wyzwalacz, taki jak ograniczenie klucza podstawowego?

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 :



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Wyrocznia wstawia tylko czas

  2. Niestandardowa funkcja Oracle IsNumber z precyzją i skalą

  3. zatwierdź po wybraniu

  4. Zapytanie SQL z użyciem dwóch dat

  5. SQL Server odpowiednik Oracle LEAST?