sql >> Databáze >  >> RDS >> Oracle

jak vytvořit spouštěč jako omezení primárního klíče?

Jen proto, že se zdá, že máte zájem vidět toto selhání, a nebrat nic z bodů APC, vypadá to, že to na první pohled funguje, pokud je to before spoušť:

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;
/

Zkompiluje se a pokud vložíte data, získáte chování, které se zdá, že chcete:

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 

Zdá se, že dělá, co chcete. Ale ne, pokud máte více než jedno sezení. V této relaci jsem se nezavázal; v jiné relaci mohu udělat:

insert into t42 values (1);

1 row created.

select * from t42;

        ID
----------
         1

1 row selected.

Hmm, to je zvláštní. No, možná je to odloženo... pojďme je zavázat oba:

commit;

select * from t42;
        ID
----------
         1
         1

2 rows selected.

Jejda. Jakmile relace neuvidí nepotvrzená data jiné relace, nebude to nikdy fungovat.

Problém s mutující tabulkou se také projeví, když vložíme více řádků do jednoho příkazu:

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> 

Dvojité oops.

I s after trigger a balíček pro vyřešení problému s mutující tabulkou, budete mít tento problém (myslím), pokud nezamknete celou tabulku pro každé vložení nebo aktualizaci. Jak řekl APC, omezení je implementováno hluboko v útrobách databáze, nikoli na této úrovni.

Ne, když máte více než jedno sezení, ne. A dokonce ani v rámci jedné relace, pokud nemáte ve sloupci index, výkon se nezmění jako count(*) bude postupně pomalejší. A pokud index máte, proč z něj v první řadě neudělat jedinečný index?

Nakonec z pokynů pro návrh spouštěčů :



  1. Potřeba uspořádat jména zaměstnanců podle jejich sloupce města

  2. php (fuzzy) hledání shody

  3. C# a MySQL .NET Connector – nějaký způsob, jak zabránit útokům SQL Injection v obecné třídě?

  4. Správa vysoké dostupnosti PostgreSQL – Část I:Automatické převzetí služeb při selhání PostgreSQL