Oracle
 sql >> база данни >  >> RDS >> Oracle

Актуализиране на тригер PL/SQL Oracle

Опитайте сложен тригер:

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

========РЕДАКТИРАНЕ - няколко въпроса и отговора ===========

В:Защо възниква грешка в променящата се таблица?
О:Това е описано в документацията:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708

В:как да избегнете грешка в променящата се таблица?
О:Документацията препоръчва използването на задействане на съединение, вижте това:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ

В:Какво е комбиниран тригер и как работи?
О:Това е огромна тема, моля, вижте документацията тук:http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD

Накратко:това е специален вид тригер, който прави psiспособен да комбинира четири типа отделни тригери:BEFORE statement , BEFORE-for each row , AFTER for each row и AFTER statament в една декларация. Това улеснява прилагането на някои сценарии, при които има нужда от предаване на някои данни от един тригер към друг. Моля, разгледайте връзката по-горе за повече подробности.

В:Но какво всъщност означава "Departments( :new.department ) := :new.department; ?
О:Тази декларация съхранява номер на отдел в асоциативен масив.

Този масив е деклариран в декларативна част на съставния тригер:

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

В документацията, свързана със съставните тригери, се казва, че:http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE

Горното означава, че Departments променливата се инициализира само веднъж в началото на цялата обработка, точно след задействане на тригера. „Продължителност на командата за задействане“ означава, че тази променлива се унищожава, след като тригерът приключи.

Този израз:Departments( :new.department ) := :new.department; съхранява номер на отдел в асоциативния масив. Намира се в BEFORE EACH ROW раздел, след което се изпълнява за всеки ред, който е актуализиран (или вмъкнат) от израза update/insert.

:new и :old са псевдозаписи, повече за тях можете да намерите тук: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Накратко::new.department извлича нова стойност на department колона- за текущо актуализиран ред (актуализирана стойност - СЛЕД актуализацията), докато :old.department дава стара стойност на тази колона (ПРЕДИ актуализацията).

Тази колекция по-късно се използва в AFTER STATEMENT , когато тригерите изберат всички актуализирани отдели (в FOR-LOOP), за всеки отдел задейства SELECT SUM(salary) ... и след това проверява дали тази сума е по-малка от 1000

Помислете за проста актуализация:UPDATE treballa SET salary = salary + 10 . Това е единичен оператор за актуализиране, но променя много редове наведнъж. Редът на изпълнение на нашия тригер е следният:

  1. Инструкцията за актуализация се задейства:UPDATE treballa SET salary = salary + 10
  2. Изпълнява се декларативният раздел на тригера, тоест:Departments променливата е инициализирана
  3. BEFORE EACH ROW секция се изпълнява отделно за всеки актуализиран ред - толкова пъти, колкото редове има за актуализиране. На това място събираме всички отдели от променени редове.
  4. AFTER STATEMENT секция се изпълнява. В този момент таблицата вече е актуализирана - всички редове вече имат нови, актуализирани заплати. Ние преглеждаме отделите, записани в Departments и за всеки проверяваме дали сумата на заплатите е по-малка или равна на 1000. Ако тази сума е> 1000 за някой от тези отдели, тогава се хвърля грешка и цялата актуализация се прекъсва и се връща назад. В противен случай тригерът завършва и актуализацията е направена (но все пак трябва да извършите тези промени).

В:Какво е асоциативен масив и защо се използва само този вид колекция, а не други колекции (променлив или вложена таблица)?
О:PL/SQL колекциите са огромна тема. Следвайте тази връзка, за да ги научите:http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005

Накратко - асоциативният масив (или таблица с индекси) е като карта в java (hashmap, treemap и т.н.) - това е набор от двойки ключ-стойност и всеки ключ е уникалната . Можете да поставите един и същ ключ много пъти в този масив (с различни стойности), но този ключ ще бъде съхранен само веднъж - той е уникален.
Използвах го, за да получа уникален набор от отдели.
Разгледайте нашия пример за актуализиране отново:UPDATE treballa SET salary = salary + 10 - тази команда засяга стотици редове, които имат същия отдел. Не искам колекция с един и същи отдел да се дублира 100 пъти, имам нужда от уникален набор от отдели и искам да изпълня нашата заявка SELECT sum()... само веднъж за всеки отдел, а не 100 пъти. С помощта на sssociative array това става автоматично - получавам уникален набор от deparments.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Задайте изчакване на връзката с базата данни в Python

  2. Използвайте Plink, за да изпълните команда (Oracle SQL заявка) на отдалечен сървър през SSH

  3. Напълно разбиране на PDO ATTR_PERSISTENT

  4. Не може да се деактивира защитата на състоянието на сесията на Oracle APEX 18.1.0.00.45 за динамични действия, актуализиращи елементи на страница

  5. Добре ли са изричните ангажименти, когато е включено автоматичното ангажиране?