Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Jak modyfikować tabele z ustawionym na niej triggerem
Forum PHP.pl > Forum > Bazy danych > Oracle
woj_tas
Witam.

Mam tabele odpowiedzi (id, tytul, kolejnosc) oraz ustawionego na niej wyzwalacz:
  1. CREATE OR REPLACE
  2. TRIGGER ODPOWIEDZI_TRG
  3. AFTER DELETE ON ODPOWIEDZI
  4. FOR EACH ROW
  5. DECLARE
  6. nr_pytania NUMBER(4);
  7. nr_kolejnosc NUMBER(4);
  8. BEGIN SELECT pytanie_id, kolejnosc INTO nr_pytania, nr_kolejnosc FROM odpowiedzi WHERE odpowiedz_id = :OLD.odpowiedz_id;
  9. UPDATE odpowiedzi SET kolejnosc = kolejnosc-1 WHERE (kolejnosc > nr_kolejnosc AND pytanie_id = nr_pytania);
  10. END;

Jak widac chciałbym w wyzwalaczu zmodyfikować kolumnę kolejność. Niestety otrzymuję błąd:
Cytat
tabela ODPOWIEDZI ulega mutacji, wyzwalacz/funkcja może tego nie widzieć


Pytanie brzmi w jaki sposób mogę działać na tabeli na której utworzony jest wyzwalacz?

Dodam tylko że znalazłem odpowiedź aby usunąć FOR EACH ROW ale niestety wtedy nie będę miał dostępu do :NEW i :OLD
lukskrodz
A probowałes usunać
FOR EACH ROW
i zamiast tego dać:
REFERENCING NEW AS NEW OLD AS OLD;
redman2
Wydaje mi sie, ze nie mozna dzialac na tabeli na ktorej masz ustawiony trigger. Poza tym to zapytanie nie ma sensu, jako ze nie wywolujesz komedny DELETE. Jaki bylby sens ustawiac trigger na siebie samego ?

Wejdz do EM i w dziale TRIGGER pozamieniaj tabele i zobacz czy sie skompiluje.

Powodzenia
ciapol
Cytat(lukskrodz @ 19.05.2008, 22:54:07 ) *
A probowałes usunać
FOR EACH ROW
i zamiast tego dać:
REFERENCING NEW AS NEW OLD AS OLD;

Po co pisać, że masło jest maślane?
Jeśli chcesz zmienić nazwę referencji to wpisujesz REFERENCING NEW AS inna_nazwa_new OLD AS inna_nazwa_OLD. A ponieważ nie zmieniłeś nic w nazewnictwie wpisujesz po prostu REFERENCING.
To raz. Dwa, Panie woj_tas nie można ustawić wyzwalacza bezpośrednio na DELETE relacji, a na perspektywie jak najbardziej :-) Kolejna sprawa jest taka, że można operować na relacji na której jest ustawiony trigger, ale należy to robić w sposób logiczny np:
  1. CREATE OR REPLACE TRIGGER weryfikacja_numeru_nowej_bandy
  2. BEFORE INSERT ON Bandy
  3. FOR EACH ROW
  4. DECLARE
  5. ile_jest bandy.nr_bandy%TYPE;
  6. BEGIN SELECT COUNT(*) INTO ile_jest FROM Bandy;
  7. IF :NEW.nr_bandy!=(ile_jest+1) THEN :NEW.nr_bandy:=(ile_jest+1); END IF;
  8. END;
  9. /
  10. SHOW ERRORS;

Powodzenia i pozdrawiam
MW
WojtusJ
Panie ciapol, oczywiście muszę się z Panem zgodzić jednak pojawiło się trochę filozofii z Pańskiej wypowiedzi...

Po pierwsze - sprawa kosmetyczna - posługuje się Pan błędną terminologią. Pojęcie "relacji" występuje jedynie w Teorii Relacyjnej, podobnie jak krotka, atrybut, dziedzina czy schemat relacji. W naszym przypadku mowa ewidentnie o modelu fizycznym relacyjnej bazy danych, zatem powinno używać się pojęcia "Tabela" po prostu :-)

Po drugie działanie triggerem na tabeli na której jest ustawiony w sposób logiczny to bardziej jakaś magia. Problem woj_tas'a pojawił się z tego względu, że wyzwalacze FOR EACH ROW oraz wszystkie wywołane pośrenio przez DELETE CASCADE nie mogą czytać ani pisać w mutating tables, czyli tabelach które wyzwoliły zmianę (z małym wyjątkiem o którym zaraz) - to jest ten problem. W starszych wersjach nie mogły również modyfikować kluczy w constraining tables.

Uściślając (wspomniany wyjątek), wyzwalacz FOR EACH ROW nie ma dostępu do innych wierszy zmieniającej się tabeli, CHYBA ŻE jest to wyzwalacz BEFORE | AFTER INSERT FOR EACH ROW wyzwolony przez wstawianie pojedynczego wiersza.

Ta 'logika' wyczerpuje temat ;-)

Powodzenia!
kshysieq
A próbowaliście używać PRAGMA AUTONOMOUS_TRANSACTION; W niektórych szczególnych przypadkach może być bardzo pomocne.
Przykład zaczerpnięty ze strony http://www.psoug.org/reference/table_trigger.html

  1. CREATE OR REPLACE TRIGGER t_trigger
  2. AFTER INSERT ON t1 FOR EACH ROW
  3.  
  4. DECLARE
  5. PRAGMA AUTONOMOUS_TRANSACTION;
  6. i PLS_INTEGER;
  7. BEGIN
  8. SELECT COUNT(*)
  9. INTO i
  10. FROM t1;
  11.  
  12. INSERT INTO t2
  13. VALUES
  14. (i);
  15. COMMIT;
  16. END;/


wiiir
no przeciez jest after delete, wiec usuwasz i dajesz :old na rekord ktorego nie ma, dlatego triger tego nie widziec biggrin.gif.. daj before

btw.. nawet nie wiedzialem ze to tak stary temat ;D
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.