MSSQL/PostgreSQL przepisywanie triggera.

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:

-- 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.

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:

-- 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.

0

udało mi się stworzyć taki zamiennik:

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

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 ??

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();
	
0

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

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:

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();

1 użytkowników online, w tym zalogowanych: 0, gości: 1