Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Trigger rekursiv (https://www.delphipraxis.net/137362-trigger-rekursiv.html)

stahli 19. Jul 2009 14:41

Datenbank: FB • Version: 2.1 • Zugriff über: IBX

Trigger rekursiv
 
Hallo alle,

ich nutze jetzt erstmals Trigger und Stored Procedure ... (muss man ja gar keine Angst vor haben ;-) und mit IBExpert geht das ja fast wie von alleine).

Jetzt will ich aber nach jeder Änderung in einer Tabelle alle Datensätze neu anpassen. Als Beispiel sei mal gegeben: "MyTable" mit den Feldern ID, A, B, und Pos.
Nach jeder Änderung in MyTable soll der Wert in Pos für alle Datensätze neu berechnet werden.
Dafür habe ich eine stored procedure CalcAllPos, erstellt, die das erledigt.

Nun rufe ich diese procedure in einem Trigger AfterPostUpdateDelete auf, was zu einem rekursiven Aufruf des Triggers und der Prozedur und einem Stacküberlauf führt.

Wie löst man das Problem am besten?

Eine Definition des neues Wertes im Trigger über new.Pos kann ich nicht verwenden, da ALLE Datensätze der Tabelle neu berechnet werden sollen.

Globale Variablen (als Flag) unterstützt FB ja offenbar nicht.
Nun könnte ich vielleicht ein Tabellenfeld dafür einführen oder ich könnte die Pos-Daten in eine eigene Tabelle "MyTablePos" auslagern und über eine ID zur "MyTable" verbinden. Änderungen in "MyTablePos" würden dann nicht noch einmal die Trigger von MyTable auslösen.

Gibt es aber vielleicht einen besseren Weg?


Stahli

TBx 19. Jul 2009 15:09

Re: Trigger rekursiv
 
Ich vermute jetzt mal, dass Du über pos die Reihenfolge der Datensätze für eine Auswertung festlegen willst.

Prinzipiell sollte das über mehrere Trigger gelöst werden:[list][*]BeforeInsert: Prüfen, ob ein Wert für pos gesetzt ist
  • ja: dann in allen Datensätzen, die einen pos-Wert >= new.pos haben pos incrementieren
  • nein: den höchsten pos-Wert ermitteln, incrementieren und in new.pos ablegen
[*] beforeUpdate: Prüfen, ob der pos-Wert geändert wurde, wenn ja:[list][*]prüfen, ob new.pos is null[list][*] ja: in allen Datensätzen, die einen Pos-Wert >= old.pos haben, den pos-Wert decrementieren, den nun höchsten pos-Wert ermitteln, incrementieren und als new.pos setzen[*]nein: prüfen, ob old.pos > new.pos[list:af58ac1ec3][*]ja: alle pos-Werte in den Datensätzen, die >new.pos und[list=1]new.pos und[list=1] old.pos haben decrementieren[/list:u:af58ac1ec3]

Ich hoffe, das hilft als Denkanstoss.

Gruß

stahli 19. Jul 2009 15:24

Re: Trigger rekursiv
 
Es ist etwas komplizierter.
Pos wird in Abhängigkeit von A + B berechnet und ist davon abhängig, wie oft A + B in der Tabelle vorkommen.
Ich kann mich daher nur auf die Tabellendaten nach irgendeiner Änderung beziehen und dabei ist es egal, ob etwas eingefügt, gelöscht oder geändert wurde (es kommt eben nur auf die neuen Daten in der Tabelle an).
Es handelt sich also um berechnete Ergebnisse, die aber alle Datensätze der Tabelle berücksichtigt.

Wenn ich die Procedure selbst starte ist ja alles ok. Nur wenn ich sie aus einen Trigger heraus aufrufe starten wie Änderungen wieder den Trigger etc.

Ich werde wohl die "berechneten Ergebnisse" in eine extra Tabelle auslagern. Das scheint mir am sinnvollsten und ich versuche das gerade mal umzusetzen ...

TBx 19. Jul 2009 15:36

Re: Trigger rekursiv
 
das ist dann eigentlich der klassische Anwendungsfall für Views. Die Daten jeweilig bei Datensatzoperationen neu zu schreiben ist überflüssig, wenn diese jederzeit berechnet werden können.

Wozu brauchst Du denn die Werte?

stahli 19. Jul 2009 15:51

Re: Trigger rekursiv
 
Es gibt eine Gruppen mit einer ID.
Innerhalb einer Gruppe gibt es Einträge von einem bestimmten Typ (Text als varchar).
Jeder Eintrag hat ein Feld Pos.
Gibt es innerhalb einer Gruppe mehrere Einträge des gleichen Typs sollen diese nummeriert werden:

Zitat:

GrId, Id, Typ, Pos
1, 1, hd, 1
1, 2, hd, 2
1, 3, dd, null
1, 4, d, null
2, 5, d, 1
2, 6, d, 2
2, 7, e, null
2, 8, d, 3
Die Numerierung soll nur erfolgen, wenn mehr als ein Eintrag pro Typ in einer Gruppe existiert.
Die Änderungen in der Tabelle sind recht selten, die Abfragen rel. häufig. Daher will ich die Ergebnisse fest in der Datenbank ablegen.
Da jede Änderung berücksichtigt werden soll, will ich die Neuberechnung gern über Trigger anstoßen...

TBx 19. Jul 2009 16:01

Re: Trigger rekursiv
 
Wodurch ergibt sich die Nummerierung in den Gruppen? Aus der Datensatzanlage? Soll diese Nummerierung editierbar sein?

stahli 19. Jul 2009 16:11

Re: Trigger rekursiv
 
Die Nummerierung ergibt sich aus der bisherigen Nummerierung und der ID.
Neue Einträge werden entsprechend angefügt.

1.md
2.md
wird hier ein Eintrag "md" angefügt erhält er Nr. 3.

1.wd
2.wd
3.wd
Wird der 2. Eintrag gelöscht der der 3. Eintrag zu Nr. 2.

1.d
2.d
Wird der 2. Eintrag gelöscht entfällt die Nummerierung für der 1. Eintrag (dann nur noch "d", da er dann der einzige Eintrag ist).


Für eine Zuweisung der Nummer muss halt immer untersucht werden, wieviele gleiche Typen es in einer Gruppe gibt.

Editierbar soll das Feld nicht sein.

mkinzler 19. Jul 2009 18:21

Re: Trigger rekursiv
 
Du könntest das Pos-Feld auch als virtuelles Feld in der Abfrage (SP) liefern

Blup 20. Jul 2009 07:15

Re: Trigger rekursiv
 
Bei so einer Datenstruktur gibt es Lock-Konflikte, wenn mehr als eine Transaktion innerhalb einer Gruppe in die Tabelle schreibt.
Bei vielen Datensätzen kann das recht langsam werden, da jede einzelne Änderung den Trigger auslöst. Im Update-Trigger muss geprüft werden, dass sich wirklich ein Feld abgesehen von POS ändert.

Das Feld POS würde ich in eine zweite Tabelle auslagern (nur ID und POS), damit entfallen automatisch rekursiven Triggeraufrufe.

stahli 20. Jul 2009 11:14

Re: Trigger rekursiv
 
Moin,

mit dem Auslagern in eine eigene extra Tabelle habe ich es jetzt gelöst.
Allerdings wäre es mir angenehmer gewesen (weniger aufwändig), wenn ein Trigger sich einfach nicht selbt auslöst oder man dies einfach über ein globales Flag abfangen könnte.

Danke
Stahli


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:13 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz