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

Aktualizuj wyzwalacz PL/SQL Oracle

Wypróbuj wyzwalacz złożony:

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

========EDIT - kilka pytań i odpowiedzi ===========

P:Dlaczego występuje błąd tabeli mutacji?
O:Jest to opisane w dokumentacji:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

P:jak uniknąć błędu tabeli mutacji?
O:Dokumentacja zaleca użycie wyzwalacza złożonego, zobacz to:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

P:Co to jest wyzwalacz złożony i jak działa?
O:To obszerny temat, zapoznaj się z dokumentacją tutaj:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

W skrócie:jest to specjalny rodzaj wyzwalacza, który umożliwia połączenie czterech typów oddzielnych wyzwalaczy:BEFORE statement , BEFORE-for each row , AFTER for each row i AFTER statament w jedną deklarację. Ułatwia realizację scenariuszy, w których zachodzi potrzeba przekazywania danych z jednego wyzwalacza do drugiego. Zapoznaj się z powyższym linkiem, aby uzyskać więcej informacji.

P:Ale co właściwie oznacza "Departments( :new.department ) := :new.department; ?
O:Ta deklaracja przechowuje numer działu w tablicy asocjacyjnej.

Ta tablica jest zadeklarowana w deklaratywnej części wyzwalacza złożonego:

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

Dokumentacja związana ze złożonymi wyzwalaczami mówi, że:http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Powyższe oznacza, że ​​Departments zmienna jest inicjowana tylko raz na początku całego przetwarzania, zaraz po odpaleniu wyzwalacza. „Czas trwania instrukcji uruchamiającej” oznacza, że ​​zmienna ta jest niszczona po zakończeniu wyzwalacza.

Ta instrukcja:Departments( :new.department ) := :new.department; przechowuje numer działu w tablicy asocjacyjnej. Znajduje się w BEFORE EACH ROW sekcji, to jest wykonywane dla każdego wiersza, który jest aktualizowany (lub wstawiany) przez instrukcję update/insert.

:new i :old to pseudorekordy, więcej na ich temat znajdziesz tutaj: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
W skrócie::new.department pobiera nową wartość department kolumna- dla aktualnie zaktualizowanego wiersza (zaktualizowana wartość - PO aktualizacji), natomiast :old.department podaje starą wartość tej kolumny (PRZED aktualizacją).

Ta kolekcja jest później używana w AFTER STATEMENT , gdy wyzwalacze wybierają wszystkie zaktualizowane działy (w FOR-LOOP), dla każdego działu uruchamia SELECT SUM(salary) ... a następnie sprawdza, czy suma ta jest mniejsza niż 1000

Rozważ prostą aktualizację:UPDATE treballa SET salary = salary + 10 . To jest pojedyncza instrukcja aktualizacji, ale zmienia wiele wierszy naraz. Kolejność wykonania naszego wyzwalacza jest następująca:

  1. Uruchomiony komunikat aktualizacji:UPDATE treballa SET salary = salary + 10
  2. Wykonywana jest deklaratywna sekcja wyzwalacza, czyli:Departments zmienna jest inicjowana
  3. BEFORE EACH ROW sekcja jest wykonywana osobno dla każdego zaktualizowanego wiersza - tyle razy, ile jest wierszy do zaktualizowania. W tym miejscu zbieramy wszystkie działy ze zmienionych rzędów.
  4. AFTER STATEMENT sekcja jest wykonywana. W tym momencie tabela jest już zaktualizowana - wszystkie wiersze mają już nowe, zaktualizowane pensje. Przechodzimy przez działy zapisane w Departments i dla każdego sprawdzamy, czy suma wynagrodzeń jest mniejsza lub równa 1000. Jeśli ta suma jest> 1000 dla któregoś z tych działów, to wyrzucany jest błąd, a cała aktualizacja jest przerywana i cofana. W przeciwnym razie wyzwalacz zakończy działanie, a aktualizacja zostanie zakończona (ale i tak musisz zatwierdzić te zmiany).

P:Co to jest tablica asocjacyjna i dlaczego używany jest właśnie ten rodzaj kolekcji, a nie inne kolekcje (tablica zmienna lub tabela zagnieżdżona)?
O:Kolekcje PL/SQL to ogromny temat. Kliknij ten link, aby się ich nauczyć:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

W skrócie - tablica asocjacyjna (lub tabela indeksowana według indeksu) jest jak mapa w Javie (hashmap, treemap itp.) - jest to zestaw par klucz-wartość, a każdy klucz jest unikalny . Możesz umieścić ten sam klucz wiele razy w tej tablicy (o różnych wartościach), ale ten klucz będzie przechowywany tylko raz - jest unikalny.
Użyłem go do uzyskania unikalnego zestawu działów.
Rozważ ponownie nasz przykład aktualizacji:UPDATE treballa SET salary = salary + 10 - to polecenie dotyka setek wierszy, które mają ten sam dział. Nie chcę, aby kolekcja z tym samym działem została zduplikowana 100 razy, potrzebuję unikalnego zestawu działów i chcę wykonać nasze zapytanie SELECT sum()... tylko raz na każdy dział, a nie 100 razy. Z pomocą tablicy skojarzeniowej odbywa się to automatycznie - otrzymuję unikalny zestaw wydziałów.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ... gdzie liczba (kolumna)> 1

  2. Funkcja pozwalająca na uzyskanie liczby dni tygodnia pomiędzy dwiema datami z wyłączeniem świąt

  3. PL/SQL Jak zwrócić wszystkie atrybuty w ROW

  4. Dlaczego TO_CHAR dodaje spację (jeden biały znak) na początku liczby?

  5. PhpStorm nie może rozwiązać kolumny dla wielu połączeń z bazą danych