Trigger für Update einer einzelnen Zeile

Probleme und Fragen zum Thema Trigger und Funktionen.
Antworten
Hanno
Benutzer
Beiträge: 72
Registriert: Do 21. Jan 2010, 15:19

Trigger für Update einer einzelnen Zeile

Beitrag von Hanno » Di 31. Jan 2017, 08:26

Hallo,

Ich habe heute eine Frage bzgl. eines Triggers. Ich habe in einer Tabelle ein Feld mit einer Gesamtstundenzahl. Diese Stundenzahl wird über einen Trigger aus verschiedenen anderen Tabellen berechnet und gefüllt. Die Zeiten stehen dabei in mehreren anderen Tabellen und werden über den Trigger zusammengezogen addiert und in das Feld eingetragen.
Jetzt habe ich ein weiteres Feld zur Validierung. Dies Feld ist Ja/Nein. Default-Wert wäre hier immer ungeprüft (Nein). Ein Admin Benutzer muss dann das Feld GEsamtdotation prüfen und von Hand auf Ja setzen. Soweit funktioniert auch alles. Jetzt ist es aber so, dass bei jeder Änderung der Gesamtdotation die Validierung wieder auf Nein gesetzt werden muss, d.h. sobald sich die Zahl im Feld Gesamtdotation ändert muss der Wert in Validierung automatisch auf Nein gesetzt werden, damit anschliessend wieder geprüft und von Hand auf Ja gesetzt werden kann.
Ich bin jetzt nicht ganz sicher, wie ich das in den Trigger der Berechnung der Gesamtdotation einbeziehen kann oder ob ich da einen zweiten Trigger setzen müsste oder wie ich das sonst bewerkstelligen kann. Hat jemand einen Tipp oder kann mir dabei helfen?
Hier wären mal der jetzige Stand.

Vielen, vielen Dank schonmal im Voraus.

CREATE TABLE public.kurse (
id_kurs serial NOT NULL PRIMARY KEY,
studienjahr varchar(50),
bezeichnung varchar,
semester integer,
notizen varchar,
ects integer,
anzahl_lektionen_pro_semester integer,
anzahl_lektionen_pro_woche integer,
anzahl_studierende integer,
id_verantwortlicher integer,
id_studiengang integer,
kuerzel varchar(30),
grunddotation numeric(18,1),
gesamtdotation numeric(18,1),
anzahl_wiederholungen varchar,
validation boolean NOT NULL DEFAULT false,
/* Keys */
CONSTRAINT kurse_pkey
PRIMARY KEY (id_kurs),
/* Foreign keys */
CONSTRAINT fk_kurse_personalbestand
FOREIGN KEY (id_verantwortlicher)
REFERENCES public.personalbestand(id_personalbestand),
CONSTRAINT fk_kurse_studiengaenge
FOREIGN KEY (id_studiengang)
REFERENCES public.studiengaenge(id_studiengang)
) WITH (
OIDS = FALSE
);


CREATE TRIGGER trigger_gesamtdotation
BEFORE UPDATE OR INSERT
ON public.kurse
FOR EACH STATEMENT
EXECUTE PROCEDURE public.moduldb_gesamtdotation();


CREATE OR REPLACE FUNCTION public.moduldb_gesamtdotation()
RETURNS trigger AS
$$
BEGIN
--UPDATE kurse set gesamtdotation = (NEW.anzahl_lektionen_pro_woche*14*2.3);
update kurse
set gesamtdotation =
(select sum(anzahl_stunden)
from stunden_kurs_gesamt
where stunden_kurs_gesamt.id_kurs = kurse.id_kurs
group by id_kurs)
where id_kurs = kurse.id_kurs;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

akretschmer
Erfahrener Benutzer
Beiträge: 7677
Registriert: So 29. Okt 2006, 13:35
Wohnort: Kaufbach, Sachsen, Germany, Germany
Kontaktdaten:

Re: Trigger für Update einer einzelnen Zeile

Beitrag von akretschmer » Di 31. Jan 2017, 09:10

in deiner Function, einfach update ... set spalte1 = ..., spalte2 = ...
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Hanno
Benutzer
Beiträge: 72
Registriert: Do 21. Jan 2010, 15:19

Re: Trigger für Update einer einzelnen Zeile

Beitrag von Hanno » Di 31. Jan 2017, 09:34

Hallo,

Werden dann nicht alle Zeilen geändert? Ich möchte ja immer nur die Zeile ändern wenn sich der Wert der Gesamtdotation geändert hat. Bei der Berechnung der Gesamtdotation geht es auch für alle Zeilen, aber die Validation soll ja nur geändert werden wenn die alte Gesamtdotation geändert hat. Wenn ich alle Werte anpasse, dann muss ich vorher prüfen, ob sich der Wert geändert hat. z.B. so:

BEGIN
update kurse
set
validation = (select
CASE WHEN
--(NEW.anzahl_wochen <> OLD.anzahl_wochen AND NEW.anzahl_lektionen <> OLD.anzahl_lektionen) AND
--(NEW.anzahl_stunden <> OLD.anzahl_stunden) AND
(NEW.gesamtdotation <> OLD.gesamtdotation)
THEN FALSE
ELSE TRUE
END),
gesamtdotation =
(select sum(anzahl_stunden)
from stunden_kurs_gesamt
where stunden_kurs_gesamt.id_kurs = kurse.id_kurs
group by id_kurs)
where id_kurs = kurse.id_kurs;
RETURN NEW;

Da ich ja ausserdem die Gesamtdotation über andere Tabellen fülle geht der trigger nur wenn ich direkt in der Tabelle kurse etwas ändere. Sobald ich aber dann in den zugehörigen Tabellen etwas ändere, Woraus ja die gesamtdotation berechnet wird) gibt es einen Fehler, weil die Spalte für NEW ja nicht bekannt ist. Das Feld für gesamtdotation gibt es ja nur in der Tabelle Kurse. Der Trigger wird aber ja trotzdem ausgeführt weil dadurch ja das Feld Gesamtdotation aktualisiert wird durch die Felder anzahl_wochen und anzahl_lektionen und anzahl_stunden in den anderen Tabellen. Irgendwie sehe ich da gerade nicht ganz durch. Geht das überhaupt oder mach ich da jetzt einen Denkfehler?
Vielen Dank nochmal im Voraus.

akretschmer
Erfahrener Benutzer
Beiträge: 7677
Registriert: So 29. Okt 2006, 13:35
Wohnort: Kaufbach, Sachsen, Germany, Germany
Kontaktdaten:

Re: Trigger für Update einer einzelnen Zeile

Beitrag von akretschmer » Di 31. Jan 2017, 10:51

irgendwie komme ich da grad nicht ganz hinterher. Du willst, wenn sich was in Tabelle X oder Y ändert, etwas in Tabelle kurse updaten (vom Verstoß gegen Normalisierung mal angesehen...). Dazu brauchst Du TRIGGER auf X und Y, die das machen. Wenn Du außerdem willst, daß bei einem Update in Kurse da auch noch Aktionen laufen, dann solltest Du da passende Trigger setzen.

Du solltest auch kein Statement-level Trigger hier nehmen, sondern Row-level (for each row). Nur so kannst Du auch auf NEW und OLD zugreifen. Und Du kannst in der Trigger-Definition auch Conditions angeben, wann dieser gefeuert werden soll (WHEN ( Condition ))

Und ja: in einem Update kann man via WHERE eingrenzen, welche Records das Update bekommen sollen.
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

Antworten