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

Aktualizujte Trigger PL/SQL Oracle

Zkuste složený spouštěč:

CREATE OR REPLACE TRIGGER compound_trigger_name
FOR  INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER

  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

     BEFORE EACH ROW IS
     BEGIN
        -- collect updated or inserted departments 
        Departments( :new.department ) := :new.department;
     END BEFORE EACH ROW;

     AFTER STATEMENT IS
        sum_sal NUMBER;
     BEGIN
      -- for each updated department check the restriction
      FOR dept IN Departments.FIRST .. Departments.LAST
      LOOP
         SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
         IF sum_sal > 1000 THEN
            raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
         END IF;
      END LOOP;
     END AFTER STATEMENT;

END compound_trigger_name;
/

========UPRAVIT – několik otázek a odpovědí ===========

Otázka:Proč dochází k chybě mutující tabulky?
Odpověď:Toto je popsáno v dokumentaci:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

Otázka:jak se vyhnout chybě mutující tabulky?
Odpověď:Dokumentace doporučuje použití spouštěcího mechanismu, viz toto:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

Otázka:Co je to složený spouštěč a jak funguje?
Odpověď:Toto je rozsáhlé téma, podívejte se prosím na dokumentaci zde:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

Ve zkratce:jedná se o speciální druh spouštěče, který umožňuje kombinovat čtyři typy samostatných spouštěčů:BEFORE statement , BEFORE-for each row , AFTER for each row a AFTER statament do jednoho prohlášení. Usnadňuje implementaci některých scénářů, ve kterých je potřeba předávat některá data z jednoho spouštěče do jiného. Další podrobnosti naleznete na výše uvedeném odkazu.

O:Ale co vlastně znamená "Departments( :new.department ) := :new.department; ?
Odpověď:Tato deklarace ukládá číslo oddělení do asociativního pole.

Toto pole je deklarováno v deklarativní části složeného spouštěče:

  TYPE Departments_t   IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
  Departments          Departments_t;

Dokumentace týkající se složených spouštěčů říká, že:http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Výše uvedené znamená, že Departments proměnná se inicializuje pouze jednou na začátku celého zpracování, hned po spuštění spouště. "Trvání příkazu spouštění" znamená, že tato proměnná je po dokončení spouštěče zničena.

Tento příkaz:Departments( :new.department ) := :new.department; ukládá číslo oddělení do asociativního pole. Je v BEFORE EACH ROW sekce, pak se provede pro každý řádek, který je aktualizován (nebo vložen) příkazem update/insert.

:new a :old jsou pseudozáznamy, více o nich najdete zde: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Ve zkratce::new.department načte novou hodnotu department sloupec- pro aktuálně aktualizovaný řádek (aktualizovaná hodnota - PO aktualizaci), zatímco :old.department poskytuje starou hodnotu tohoto sloupce (PŘED aktualizací).

Tato kolekce je později použita v AFTER STATEMENT , když spouštěče vyberou všechna aktualizovaná oddělení (ve FOR-LOOP), pro každé oddělení se spustí SELECT SUM(salary) ... a poté zkontroluje, zda je tento součet menší než 1000

Zvažte jednoduchou aktualizaci:UPDATE treballa SET salary = salary + 10 . Toto je jeden příkaz aktualizace, ale mění mnoho řádků najednou. Pořadí provádění našeho spouštěče je následující:

  1. Spustí se aktualizační prohlášení:UPDATE treballa SET salary = salary + 10
  2. Je provedena deklarativní část spouštěče, to znamená:Departments proměnná je inicializována
  3. BEFORE EACH ROW sekce se provádí samostatně pro každý aktualizovaný řádek - tolikrát, kolikrát je řádků k aktualizaci. Na tomto místě shromažďujeme všechna oddělení ze změněných řádků.
  4. AFTER STATEMENT sekce je provedena. V tuto chvíli je již tabulka aktualizována – všechny řádky již mají nové, aktualizované platy. Procházíme odděleními uloženými v Departments a u každého zkontrolujeme, zda je součet platů menší nebo roven 1000. Pokud je tento součet> 1000 pro některé z těchto oddělení, dojde k chybě a celá aktualizace se přeruší a vrátí zpět. V opačném případě spoušť skončí a aktualizace je dokončena (ale tyto změny musíte stejně provést).

O:Co je to asociativní pole a proč se používá právě tento druh kolekce, a nikoli jiné kolekce (varray nebo vnořená tabulka)?
A:Kolekce PL/SQL jsou obrovské téma. Chcete-li se je naučit, klikněte na tento odkaz:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Ve zkratce – Asociativní pole (nebo index podle tabulky) je jako mapa v jazyce Java (hashmap, treemap atd.) – je to sada párů klíč–hodnota a každý klíč je unikátní . Do tohoto pole můžete vložit stejný klíč mnohokrát (s různými hodnotami), ale tento klíč bude uložen pouze jednou - je jedinečný.
Použil jsem ho k získání jedinečné sady oddělení.
Znovu zvažte náš příklad aktualizace:UPDATE treballa SET salary = salary + 10 - tento příkaz se dotkne stovek řádků, které mají stejné oddělení. Nechci kolekci se stejným oddělením duplikovaným 100krát, potřebuji jedinečnou sadu oddělení a chci provést náš dotaz SELECT sum()... pouze jednou pro každé oddělení, nikoli 100krát. S pomocí sssociativního pole se to děje automaticky – získám jedinečnou sadu oddělení.




  1. Jak nahradit ' nebo jakýkoli speciální znak při použití XMLELEMENT Oracle

  2. CakePHP 1.3 - Neznámý sloupec v klauzuli where

  3. Měl by být sloupec primárního klíče Sequential Guid seskupený index?

  4. PostgreSQL 10 v systému Linux – LC_COLLATE locale en_US.utf-8 není platný