MSSQL/PostgreSQL przepisywanie triggera.

MSSQL/PostgreSQL przepisywanie triggera.
BI
  • Rejestracja:około 12 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0

Witam, staram się przepisać bazę danych oraz oprogramowanie do niej na PostgreSQL, udało mi się przepisać skrypt tworzący, funkcje, widoki itd ale na triggerach mam problem :(
Mam wrażenie że postgres jest bardzo ubogi w stosunku do mssql ponieważ nie mogę nawet znaleźć porządnego poradnika. Proszę o pomoc z tym wyzwalaczem:

Kopiuj
-- Wyzwalacz który zamiast usunąć z bazy danych stanowisko, 
-- archiwizuje je w tej samej tabeli w kolumnach które normalnie są nieużywane i mają wartość NULL.
-- W przypadku gdy stanowisko zostało już wcześniej usunięte np, przez kogoś innego, wyzwalacz wydrukuje specjalną informację.
CREATE TRIGGER del_stan ON stanowisko
INSTEAD OF DELETE
AS
	DECLARE @id INT, @name Varchar(20)
	SET @id=(SELECT id_stanowisko FROM deleted)
	SET @name=(SELECT nazwa FROM deleted)

	BEGIN
		IF (77777.00)=(SELECT stara_pensja FROM stanowisko WHERE id_stanowisko=@id)
		  BEGIN
		  	PRINT 'Stanowisko '+@name+'zostało zarchiwizowane.'
			UPDATE stanowisko SET stara_pensja=pensja_godz		WHERE id_stanowisko=@id
			UPDATE stanowisko SET stare_godz=min_ilosc_godz		WHERE id_stanowisko=@id
			UPDATE stanowisko SET data_wygasniecia = GETDATE()	WHERE id_stanowisko=@id
			UPDATE stanowisko SET pensja_godz = 0				WHERE id_stanowisko=@id
			UPDATE stanowisko SET min_ilosc_godz = 0			WHERE id_stanowisko=@id
		  END
		 ELSE
		  BEGIN
			PRINT 'Operacja nie powiodła się ponieważ:'
			PRINT 'Stanowisko '+@name+'zostało zarchiwizowane wcześniej.'
		  END
	END
GO

mój problem polega na tym że używam tam tabeli 'deleted' a z tego co wyczytałem (w sumie nie wyczytałem bo nie znalazłem info) takiej tabeli w PSQL po prostu nie ma.

OA
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 10 lat
  • Postów:95
1

http://www.postgresql.org/docs/9.2/static/sql-createtrigger.html
http://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html
Do starych (nowych) rekordów można odwoływać się poprzez old.x (new.x), gdzie x jest polem tabeli.

W tym przypadku kod będzie wyglądał mniej więcej tak:

Kopiuj
-- Wyzwalacz który zamiast usunąć z bazy danych stanowisko, 
-- archiwizuje je w tej samej tabeli w kolumnach które normalnie są nieużywane i mają wartość NULL.
-- W przypadku gdy stanowisko zostało już wcześniej usunięte np, przez kogoś innego, wyzwalacz wydrukuje specjalną informację.
CREATE FUNCTION trig_del_stan() RETURNS trigger AS $$
BEGIN
    INSERT INTO stanowisko VALUES (OLD.*);
    IF 77777.00 = OLD.stara_pensja
    THEN
        RAISE NOTICE 'Stanowisko % zostało zarchiwizowane.', OLD.nazwa;
        UPDATE stanowisko
           SET stara_pensja = pensja_godz
             , stare_godz = min_ilosc_godz
             , data_wygasniecia = NOW()
             , pensja_godz = 0
             , min_ilosc_godz = 0
         WHERE id_stanowisko = OLD.id_stanowisko;
    ELSE
        RAISE NOTICE 'Operacja nie powiodła się ponieważ:';
        RAISE NOTICE 'Stanowisko % zostało zarchiwizowane wcześniej.', OLD.nazwa;
    END IF;
END;
$$ LANGUAGE PLPGSQL;

CREATE TRIGGER del_stan ON stanowisko
    AFTER DELETE FOR EACH ROW EXECUTE PROCEDURE trig_del_stan();

Uwaga: Kodu nie testowałem i nie mam jak go uruchomić, gdyż nie mam dostępu do żadnej bazy danych SQL. Mogą być jakieś drobne błędy.

edytowany 6x, ostatnio: Oak
BI
"INSTEAD OF triggers (which are always row-level triggers, and may only be used on views)" I niestety wlasnie dostaje błąd że taki trigger nie moze byc uzyty na tabeli ;/
OA
Spróbuj teraz. Może niezbyt wyrafinowany sposób, ale powinien zadziałać. ;)
BI
ERROR: syntax error at end of input LINIA 5: FROM OLD.*; nie łapię tego, non stop jakies chore errory :|
BI
  • Rejestracja:około 12 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0

udało mi się stworzyć taki zamiennik:

Kopiuj
CREATE FUNCTION del_stan()
RETURNS TRIGGER AS $$
	BEGIN
		IF (77777.00)=(OLD.stara_pensja) THEN
		  	RAISE NOTICE 'Stanowisko zostalo zarchiwizowane.';
			NEW.stara_pensja=OLD.pensja_godz;
			NEW.stare_godz=OLD.min_ilosc_godz;
			NEW.data_wygasniecia =(CURRENT_DATE);	
			NEW.pensja_godz = 0;
			NEW.min_ilosc_godz = 0;
		ELSE
			RAISE NOTICE 'Operacja nie powiodla sie poniewaz:';
		END IF;
	END;
$$LANGUAGE'plpgsql';

CREATE TRIGGER del_stan
AFTER DELETE ON stanowisko
FOR EACH ROW EXECUTE PROCEDURE del_stan();

Niestety jak próbuje usunąć to dostaję ERROR:
ERROR: record "new" is not assigned yet
SZCZEGÓŁY: The tuple structure of a not-yet-assigned record is indeterminate.
KONTEKST: PL/pgSQL function "del_stan" line 5 at assignment

OA
NEW używa się przy insert/update. Przy delete masz do dyspozycji tylko OLD.
BI
  • Rejestracja:około 12 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0

Po kilku próbach ten kod nie wywala errora. Jednak jego wadą jest to że najpierw usuwa a później chce zaktualizować tabele dla nieistniejącego rekordu (bo przed chwilą go usunął). Więc trigger działa ale nic nie robi ;/ Nie rozumiem dlaczego nie można zastosować triggera INTEAD OF dla tabeli, może jest na to jakieś obejście ??

Kopiuj
CREATE oR REPLACE FUNCTION trig_del_stan() RETURNS TRIGGER AS $$
BEGIN
 /*   INSERT INTO stanowisko
    (SELECT * FROM OLD.*;) */
    IF 77777.00 = OLD.stara_pensja
    THEN
        RAISE NOTICE 'Stanowisko % zostalo zarchiwizowane.', OLD.nazwa;
        UPDATE stanowisko
           SET stara_pensja = pensja_godz
             , stare_godz = min_ilosc_godz
             , data_wygasniecia = NOW()
             , pensja_godz = 0
             , min_ilosc_godz = 0
         WHERE id_stanowisko = OLD.id_stanowisko;
    ELSE
        RAISE NOTICE 'Operacja nie powiodla sie poniewaz:';
        RAISE NOTICE 'Stanowisko % zostalo zarchiwizowane wczesniej.', OLD.nazwa;
    END IF;
	RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;
 
CREATE TRIGGER del_stan 
    AFTER DELETE ON stanowisko FOR EACH ROW EXECUTE PROCEDURE trig_del_stan();
	
BI
to zapewne dlatego że zakomentowałem INSERT tam na górze, jednak gdy jest to aktywne to wywala ERROR: Near SELECT * FROM OLD.*;
OA
Tak pewnie dlatego. Spróbuj teraz. Jak już mówiłem nie mam gdzie tego przetestować, a kodu SQL nie pisałem przez jakieś pół roku. ;)
0

Spróbuj zamiast AFTER w trigerze użyć BEFORE, a w funkcji na końcu RETURN NULL, wtedy operacja niczego nie powinna zmieniać

BI
ERROR: duplicate key value violates unique constraint "stanowisko_pkey" SZCZEGĂĹY: Key (id_stanowisko)=(6) already exists. KONTEKST: SQL statement "INSERT INTO stanowisko VALUES (OLD.*)" PL/pgSQL function "trig_del_stanxx" line 3 at SQL statement Próbowałem różnych metod, czasem jak 'zadziałało' to wydrukowało mi tylko te RAISE NOTICE ale jak sprawdzalem potem tabele to nic sie tam nie zmienilo.
BI
  • Rejestracja:około 12 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
1

Odnalazłem błąd, znajdował się on w moim głupim niedopatrzeniu. Jestem przyzwyczajony do MSSQL i tam mi się raczej takie rzeczy nie zdarzały :) Mianowicie miałem 3 funkcje i 3 triggery nałożone na tabelę stanowisko. Ta funkcja poniżej jest jak najbardziej prawidłowa. Errory wywalały stare wersje tej funkcji których nie usunęłem. 2 dni prób i denerwowania się po to żeby w tak banalny sposób rozwiązać problem.
Bardzo dziękuję za pomoc bo ostatecznie to jednak pomysł jest użytkownika Oak.
Pozdrawiam.
:)

Wersja działająca jakby ktoś miał w przyszłości problem:

Kopiuj
CREATE OR REPLACE FUNCTION trig_del_stanx() RETURNS TRIGGER AS $$
BEGIN
   INSERT INTO stanowisko VALUES (OLD.*);
    IF 77777.00 = OLD.stara_pensja
    THEN
        RAISE NOTICE 'Stanowisko % zostalo zarchiwizowane.', OLD.nazwa;
        UPDATE stanowisko
           SET stara_pensja = pensja_godz
             , stare_godz = min_ilosc_godz
             , data_wygasniecia = NOW()
             , pensja_godz = 0
             , min_ilosc_godz = 0
        WHERE nazwa = OLD.nazwa;
		RETURN NEW;
    ELSE
        RAISE NOTICE 'Operacja nie powiodla sie poniewaz:';
        RAISE NOTICE 'Stanowisko % zostalo zarchiwizowane wczesniej.', OLD.nazwa;
		RETURN NULL;
    END IF;

END;
$$ LANGUAGE PLPGSQL;
 
CREATE TRIGGER del_stanx
    AFTER DELETE ON stanowisko FOR EACH ROW EXECUTE PROCEDURE trig_del_stanx();
edytowany 1x, ostatnio: bizarri

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.