Mittels einer RULE eine UPDATE-Abfrage ändern ...

Hallo,

ich habe folgendes Problem:

Ich versuch mittels einer Regel (RULE) bei jeder Änderung (UPDATE) einer bestimmten Tabelle in der betreffenden Relation einen TIMESTAMP in das dafür vorgesehenes Datumsfeld zu setzen.

Also in etwa so …

CREATE RULE rule_name
AS ON UPDATE
TO tabelle
DO
UPDATE tabelle
SET timeNeu = ‘now’;

Wie nicht anders zu erwarten führt das ganze zu einer Rekursion :angry: .

Im PG-Handbuch heißt es, das man mittels einer Regel die eigentliche Abfrage (hier das UPDATE) verändern kann … und genau das will ich ja … aber wie mache ich das, wenn sich die Änderung auf die gleiche Tabelle bezieht ?!

Bin für jede Hilfe dankbar !!!

Andreas

Nehme einen TRIGGER dafür und alles wird gut.

Andreas

Hallo Andreas

habe Deinen Hinweis wie folgt ausprobiert:

Zwei Tabellen:

CREATE TABLE tabelle
(
id serial NOT NULL, – ID, Primärschlüssel
wert varchar(20),
t_stamp timestamp,
CONSTRAINT tabelle_pkey PRIMARY KEY (id)
)

CREATE TABLE tabelle_hist
(
id int4 NOT NULL,
wert varchar(20),
t_stamp timestamp
)

eine Funktion:

CREATE OR REPLACE FUNCTION table_function_histo()
RETURNS “trigger” AS
$BODY$
BEGIN
INSERT INTO tabelle_hist (id, wert, t_stamp)
VALUES (OLD.id, OLD.wert, OLD.t_stamp);
UPDATE tabelle
SET t_stamp = ‘now’
where OLD.id = id;
RETURN new;
END;
$BODY$
LANGUAGE ‘plpgsql’ VOLATILE;
ALTER FUNCTION table_function_histo() OWNER TO postgres;

… und natürlich den TRIGGER:

CREATE TRIGGER trigger_upd
AFTER UPDATE
ON tabelle
FOR EACH ROW
EXECUTE PROCEDURE table_function_histo();

Sobald ich jedoch einen ‘wert’ in der Tabelle ‘tabelle’ ändere resultiert daraus eine endlose Rekursion.

Ginge es um meine Datenbank, würde ich die Timestamps zum protokollieren in eine extra Tabelle auslagern … hätte ja auch noch andere Vorteile.

Der Sinn des UPDATES von dem Timestamp bei jeder Änderung in der Originaltabelle (im Bsp. also ‘tabelle’) ist die Berücksichtigung bei umfangreichen Matching-Läufen der Datenbank.

Unter Informix kann man den Wert im Trigger direkt mittels ‘INTO’ in der betreffenden Tabelle ändern z.B. so:


FOR EACH ROW
EXECUTE PROCEDURE getTimestamp() INTO NEW.t_stamp;

wobei getTimestamp() einfach einen aktuellen Timestamp zurückliefert.

Kann man ggf. den TRIGGER so einrichten, das sich das UPDATE nur auf die Pseudo-Relation ‘NEW’ bezieht ?!

Viele Grüße,

Andreas

  1. Du willst den neu einzufügenden Datensatz noch verändern (NEW.t_stamp setzen). Dazu brauchst Du einen before - Trigger.

  2. Du darfst nicht wieder UPDATE aufrufen, da kommt die Rekursion. Statt dessen modifizierst Du NEW.t_stamp. Dein Beispiel sollte in etwa wie folgt funktionieren:

create or replace function tf() returns TRIGGER as $$
begin
INSERT INTO tabelle_hist (id, wert, t_stamp)
VALUES (OLD.id, OLD.wert, OLD.t_stamp);
NEW.t_stamp := now();
return NEW;
end;
$$ language plpgsql;

create trigger t1 before update on tabelle for each row execute procedure tf();

Andreas

Noch nachzutragen ist, daß now() den Startzeitpunkt einer TX zurückgibt. Falls es Dich wundern sollte, warum alle
Werte, die in einer TX geupdatetet wurden, exakt denselben Timestamp haben, dann tausche now() gegen timeofday() aus.

Andreas

Super …

Jetzt klappt es wie gewünscht :slight_smile: .
Großes Lob an Dein Engagement und Dein Fachwissen … so macht Postgres erst richtig Spaß !

Vielen vielen Dank !!!


Andreas