![]() |
Datenbank: MariaDB • Version: 10.1.13 • Zugriff über: FireDac
Trigger auf Datenbankebene?
Hallo, ich habe folgendes Anliegen, das zunächst ganz trivial erscheinen mag.
Vorab: Ich bin kein Datenbankexperte. Ich möchte das bei gewissen Tabellenoperationen(insert, update...) etwas in diesen Datensatz geschrieben wird. Typische Funktion für einen (tabellenbezogenen) Trigger. Nun will ich aber im Nachhinein nicht bei ein paar Hundert Tabellen einen Trigger hinterlegen. Ich hätte gerne das ich das eine Ebene höher einmalig hinterlege: in der Datenbank an sich. Wie kann ich also auf der Datenbankebene das Ereignis "User xx hat in der Tabelle yy einen Datensatz hinzugefügt" abfangen um dann wiederum auf diese Tabelle/Datensatz zuzugreifen und entsprechende Einträge(z.B. Username und Datum) vorzunehmen. (Mein Ansatz: Die Datenbank überwacht doch soweiso alles was in den Tabellen passiert - über z.B. die Sicherheit. Aber WIE zapf ich das an?) Danke für eure Hilfe. |
AW: Trigger auf Datenbankebene?
Ich wüsste jetzt nicht, dass sowas im SQL geht.
Aber du kannst dir über ein SELECT alle Tabellen auflisten lassen und dann für jede Tabelle ein CREATE TRIGGER ausführen und so deine Trigger-Funktion überall dran hängen. |
AW: Trigger auf Datenbankebene?
Mein Problem ist das ich in den Datensatz den Benutzername eintragen will. Dieser ist aber der Name mit der er sich in der Anwendung
angemeldet hat und nicht der mit dem in der Datenbank angemeldet ist. Ich müsste also dem (Tabellen)Trigger einen Parameter übergeben(Username) - und da scheitere ich. Ich hatte die Idee eine "Übersetzungspabelle" beim Anmelden in die Anwendung zu pflegen. Da steht dann drin dass der Datenbankuser_xx den Anwendung_Username_yy hat(wird beim ausloggen wieder gelöscht). Der Trigger sollte nun in dieser Tabelle nachschauen wie der Anwendung_Username lautet und diesen Namen dann in den betroffenen Datesatz posten. Da die Einträge in jeder Tabelle identisch sind(Name, Datum) brauche ich nur einen Trigger (oder eine SP). |
AW: Trigger auf Datenbankebene?
Zitat:
Ich glaub aber mit Deiner Trigger-über-alle-Tabellen-Idee sieht es schlecht aus. Das wirst Du einzeln machen müssen. |
AW: Trigger auf Datenbankebene?
Im CREATE TRIGGER kann man je nach DBMS einen Funktions-Aufruf oder gar ein "beliebiges" SQL-Statement ausführen. (meistens sind die Trigger-Funktionen ohne Parameter und haben nur die impliziten Parameter wie NEW, OLD usw., aber man kann fast immer auch weitere Parameter in die Funktion einbauen und beim Aufruf übergeben)
Das wird aber alles User-unabhängig in der DB registriert und ausgeführt. Du könntest eine Session-Variable (falls MariaDB sowas kennt) nach dem DB-Connect setzten und Diese in dem Trigger verwenden. |
AW: Trigger auf Datenbankebene?
Wäre ein zentrales BeforePost-Event auf Programmebene eventuell eine Alternative? Das wäre zudem noch datenbankunabhängig.
|
AW: Trigger auf Datenbankebene?
Ich würde es im Programm realisieren: In deiner Zugriffskomponente (vermutlich Query) gibt es das Event BeforePost, hier kannst du den Benutzernamen ermitteln und in die gewünschten Tabellenfelder eintragen.
Grüße Mikhal Da war einer schneller... |
AW: Trigger auf Datenbankebene?
Zitat:
Was genau meinst du mit "weitere Parameter"? Man kann dem Trigger ohne Umwege ja keine Parameter übergeben. Oder meinst du damit eine Funktion/Prozedur die innerhalb eines Triggers aufgerufen wird? |
AW: Trigger auf Datenbankebene?
Mit MariaDB hast Du da wohl schlechte Karten
Zitat:
|
AW: Trigger auf Datenbankebene?
Zitat:
|
AW: Trigger auf Datenbankebene?
CREATE TRIGGER wirft da aber doch hoffentlich einen Fehler, wenn man einen zweiten Trigger erstellen will? :stupid:
Meistens hat man doch in etwa sowas:
SQL-Code:
Bei einigen DBMS kann man da aber auch Parameter bei den Trigger-Funktionen nutzen.
CREATE FUNCTION TriggerFunction() ...;
CREATE TRIGGER TriggerName ON Table ... DO TriggerFunction();
SQL-Code:
Und die selbe Trigger-Funktion kann man auch an mehrere Tabellen hängen.
CREATE FUNCTION TriggerFunction(Param VARCHAR) ...;
CREATE TRIGGER TriggerName ON Table ... DO TriggerFunction('abc'); Es gibt fast immer irgendwelche virtuellen Datenbank-Schema-Tabellen, wo man eine Liste aller aktuell existierenden Tabellen auslesen kann und dann entweder clientseitig oder DB-seitig über einen EXECUTE-Befehl nacheinander die vielen CREATE TRIGGER zusammensetzen und ausführen.
SQL-Code:
CREATE FUNCTION TriggerFunction() ...;
CREATE TRIGGER TriggerName ON TableA ... DO TriggerFunction(); CREATE TRIGGER TriggerName ON TableB ... DO TriggerFunction(); CREATE TRIGGER TriggerName ON TableC ... DO TriggerFunction(); |
AW: Trigger auf Datenbankebene?
|
AW: Trigger auf Datenbankebene?
Zitat:
Delphi-Quellcode:
unit FDQueryInterposer;
interface type TFDQuery = class(FireDAC.Comp.Client.TFDQuery) protected procedure DoBeforePost; override; end; implementation procedure TFDQuery.DoBeforePost; begin { hier bei Bedarf die entsprechenden Felder setzen } inherited; end; end. |
AW: Trigger auf Datenbankebene?
Zitat:
wenn ich das richtig im Kopf habe, arbeitest Du häufig mit Postgres? Da kann man beliebige Triggerfunktionen an den Trigger hängen, auch für mehrere Trigger/Tabellen die gleiche Triggerfunktion. Hab ich neulich noch für eine Log Funktion/Werteänderung gemacht. Das geht aber so easy nicht mit jeder Datenbank. Um es straight forward zu lösen, müsste m.E. tatsächlich ein Usermapping mit einer Tabelle, die aktive Sitzungen notiert, erfolgen. Daraus könnte sich dann ein Insert/Update/ Trigger pro Tabelle bedienen (delete fällt ja weg bei der Konstruktion). Ich habe bei dem erwähnten Log Mechnismus oben, nach der Erstellung der Trigger "blinde Updates" (alter Wert = neuer Wert) über alle relevanten Daten laufen lassen und so nachträglich mit etwas Handarbeit "historische" Logdaten für initiales Insert und Update (=StatusQuo) erzeugt. Nicht geloggte Userdaten usw. lassen sich damit natürlich im Nachhinein nicht erfinden. Aber man hat dennoch für künftiges Reporting einen einheitlichen Stand. In einem reinen C/S System mit nur einem Client (einer Art) kann man natürlich auch über den Client arbeiten. Hier kann man auch problemlos weitere Daten verwenden, Rechnername usw. bei Mehrfachanmeldung oder was man so braucht. |
AW: Trigger auf Datenbankebene?
Eine BeforePost-Methode kann man mehreren Datenbankkomponenten zuweisen.
Beispiel:
Delphi-Quellcode:
Nachteil: Wird, am Programm vorbei, direkt auf der Datenbank gearbeitet oder mit anderen Clients, fehlen die im BeforePost gesetzten Informationen natürlich.
type
TForm1 = class(TForm) qryAnschriften: TZQuery; // oder sonstein genutzter Komponententyp qryRechnungen: TZQuery; // oder sonstein genutzter Komponententyp ... procedure AnyTableBeforePost(DataSet: TDataSet); ... procedure TForm1.FormCreate(Sender: TObject); begin qryAnschriften.BeforePost := AnyTableBeforePost; qryRechnungen.BeforePost := AnyTableBeforePost; ... end; procedure TForm1.AnyTableBeforePost(DataSet: TDataSet); begin DataSet.FieldByName('Username').AsString := DeineGetUserNameFunktionOderVariabelOderSowas; DataSet.FieldByName('Datum').AsString := Now; end; |
AW: Trigger auf Datenbankebene?
Zitat:
![]() Hier klingt es sogar danach, dass man auch direkt ganze SQL-Statements da ausführen lassen kann, anstatt nur eine TriggerFunktion aufzurufen. |
AW: Trigger auf Datenbankebene?
Zitat:
Gruß K-H |
AW: Trigger auf Datenbankebene?
Ja, das ist wohl so. Aber eine solche Forderung geht aus der Frage des TE nicht hervor. Wahrscheinlich wurde die Anforderung erst später angefragt.
Grundsätzlich ist die Verwendung eines Datenbank-Triggers hier der bessere Weg, wenn man diese Daten grundsätzlich bei jedem Insert- oder Update-Statement verwenden möchte. Aber dann benötigt der TE eine Tabelle mit den Benutzern, gegen die sich die Anwender anmelden müssen, damit er die Namen ziehen kann. War auch mein erster Gedanke, aber ist wohl beim TE nicht vorgesehen oder war nicht geplant. Wenn ich es richtig verstanden habe, werden DB-User angemeldet, die über eine Rolle verfügen. Und ja, er muss die Trigger für jede Tabelle anlegen, ein Aufwand, den er nicht treiben wollte. Über das Event muss er das dann aber auch machen, kann aber wie oben beschrieben eine Standard-Routine verwenden, um den Aufwand zu reduzieren. Grüße Mikhal |
AW: Trigger auf Datenbankebene?
Zitat:
Wenn es wasserdicht sein soll, müssen solche Operationen auf dem DB Server erfolgen. Wenn ich ein C/S System so definiere, dass mein (Delphi)Client den einzigen Zugriff hat (und diesen Zustand auch erfolgreich sicherstellen kann), dann kann ich natürlich hier alle möglichen Mätzchen machen, von Logging bis Business Logic. Sobald mehr als ein System auf die DB durchgreift (vor allem schreibend), bin ich natürlich gekniffen. Theoretisch entgleitet das bereits, wenn ich einen Release Candidate des gleichen Sytems auf eine Produktivdb loslasse. Naja, ich will den Teufel nicht an die Wand malen. Wenn man weiß was man tut, ist vieles möglich. Ich hatte allerdings die Anforderung des TE so verstanden, dass er nicht alle / so viel Altdaten "nachverarbeiten" will. Aber vlt geht es darum gar nicht. Zitat:
Aber das von Dir erwähnte Verfahren kenne ich so halt von Postgres und eben nicht von Maria. |
AW: Trigger auf Datenbankebene?
Zitat:
Gruß K-H |
AW: Trigger auf Datenbankebene?
Zitat:
Es gibt halt Freunde der Persistenzsysteme, die DB Blackbox Fans usw. die einfach die DB tauschen können. Und es gibt die sagen wir "traditionelle" Seite. Da würde ich mich auf jeden Fall einsortieren. Sicher gibt es auch Kompromisse. Ein App Server an einer DB ist für sich genommen auch ein C/S System, dass man nach den klassischen Regeln fahren kann. Es spricht ja nichts dagegen, andere Wege zu gehen oder andere Prioritäten zu setzen. Man muss sich halt bewusst sein, was das bedeutet. Offenbar ist es ja wohl so, dass viele Delphi im DB Bereich so einsetzen, dass die komplette Business Logik in der Anwendung liegt. Bei spezialisierten, homogenen Systemen ist das wohl okay. Und es hat ja durchaus ein paar positive bzw. willkommene Nebeneffekte. Die Business Logik und die Constraints kann mir keiner "klauen" oder einfach per Datenmodell kopieren. Ich habe schon high end Systeme gesehen, wo mir schlecht wurde, kein einziger Konstraint, auch nicht für foreign keys, fürchtliche Namensgebung, also inkonsistent usw usf. Und da kann man doch nur zu dem Schluss kommen, dass es primär um Obfuscation geht. Solange ich Robustheit, Transaktionssicherheit, Konsistenz gewährleisten kann ist ja alles gut. Ich habe allerdings oft den Eindruck, dass die Probleme vielen gar nicht so klar sind. Ebensowenig die Möglichkeiten die ein stinknormales DB System von Haus aus bietet. Und zur Großschreibung: wahrscheinlich mach ich mich mit Beiträgen wie diesen eh schon zum Affen. |
AW: Trigger auf Datenbankebene?
Zitat:
Sobald irgendetwas (und sei es das Antwortverhalten) die Kommunikation zwischen Client und Server stört, bekommst die Datenhack. Zitat:
[Welcher Chef will schon eine DB verbessern, wenn es bisher auch so ohne große Probleme ging?] Zitat:
Darum ein solidarisches OinkOink K-H P.S. @all Nein, das ist kein Rundumschlag, und ich weiß, daß hier genug Leute mitlesen, die das nicht für die Erbsenzählerei von ein paar Spinnern abtun. |
AW: Trigger auf Datenbankebene?
Zitat:
Mein Eindruck aus ca. 30 Jahren Programmiererfahrung ist eher, dass ein nicht unerheblicher Teil der Programmierer (die ich habe kennen lernen dürfen, also nicht allgemeinglobalgalaktisch) und die Software schrieben, deren Datenhaltung eine Datenbank voraussetzte, über erschreckend geringe Datenbankkenntnisse verfügten. Daraus resultiert dann eben auch, dass man alles im Programm macht (egal welche Mengengerüste da zu verarbeiten sind) und die Datenbanklogik gegen 0 tendiert. Hauptsache die Daten sind irgendwie in der Datenbank und können mit "dem eigenen Programm" sinnvoll verarbeitet werden. Aber das jetzt weiter auszuführen wäre arg OffTopic. |
AW: Trigger auf Datenbankebene?
Hach, soviel Zuspruch ist schon irgendwie tröstlich.
:) Aber es geht ja nicht um meine Bedenkenträgerschaft. Und bis jetzt kam noch kein Hinweis, dass all die Einwände berechtigt sind. Also ist es eine Standalone Anwendung oder nicht,, Die Frage wäre, ob der TE noch mitverfolgt, was hier geschrieben wird, bzw. ob man noch konkrete Hilfestellung leisten kann oder er schon "geflüchtet" ist. Dazu ein Vorschlag was die "Parameter" Frage angeht. Wenn es eine Mapping Tabelle gibt, die gepflegt ist, kann ich eine Funktion schreiben, die mir den gemappten User anhand des eingeloggten Users liefert. Die rufe ich im Triggerbody auf und hab was ich brauche, ohne Parameter. Dann ist es nur etwas Fleißarbeit, alle Trigger zu schreiben (oder zu generieren). Einzige(?) Voraussetzung wäre dann nur, dass nicht bereits Trigger vorhanden sind. Die müssten man dann bei Mariadb offenbar mergen? |
AW: Trigger auf Datenbankebene?
Ausgehend von
![]() Gegeben sei:
SQL-Code:
Zuerst wird Trigger_2 ausgeführt, dann Trigger_1 und anschließend Trigger_3.
CREATE TRIGGER Trigger_1 AFTER UPDATE ON Table_1 ...;
CREATE TRIGGER Trigger_2 BEFORE UPDATE ON Table_1 ...; CREATE TRIGGER Trigger_3 AFTER UPDATE ON Table_1 ...; Wenn ich das halbwegs richtig sehe, müsste man hier also automatisch für alle Tabellen einen zusätzlichen Trigger generieren können, der, da zuletzt erstellt, auch zuletzt ausgeführt wird. Im Trigger kann man dann eine Funktion aufrufen, die den Usernamen, auf einem der hier bereits beschriebenen Wege, ermittelt und in die Datenbank schreibt. Ungefähr sowas sollte sinngemäß gehen:
SQL-Code:
Was ich nicht habe finden können ist, ob ein Trigger auch für mehrere Ereignisse aufgerufen werden kann, also ein
CREATE TRIGGER Tabellenname_Insert
BEFORE INSERT ON Tabellenname REFERENCING NEW ROW AS New FOR EACH ROW BEGIN ATOMIC SET New.UserName = FuntionZurBenutzernemenermittlung; SET New.Datum = Current_Date; END
SQL-Code:
BEFORE INSERT OR UPDATE ON Tabellenname
Es scheint aber eher nicht der Fall zu sein, so dass halt je Tabelle zwei Trigger benötigt werden:
SQL-Code:
Inhaltlich können sie identisch sein.
CREATE TRIGGER Tabellenname_Insert BEFORE INSERT ON Tabellenname
CREATE TRIGGER Tabellenname_UPDATE BEFORE UPDATE ON Tabellenname Die oben verlinkte Dokumentation zu MariaDB ist sehr ausführlich und sollte für alle MariaDB-Nutzer zur Pflichtlektüre gehören und als ersten Anlaufstelle bei Fragen dienen. Der Triggerquelltext läßt sich vermutlich sogar per SQL über INFORMATION_SCHEMA.TABLES generieren, sowas in der Art:
SQL-Code:
Das Ergebnis müsste man dann irgendwie per Batch oder so abarbeiten.
select
ConCat('CREATE TRIGGER TRI_',Table_Name, ' BEFORE INSERT ON ',Table_Name, ' REFERENCING NEW ROW AS New FOR EACH ROW', ' BEGIN ATOMIC', ' SET New.UserName = FuntionZurBenutzernemenermittlung;' ' SET New.Datum = Current_Date;', ' END') as SQL_Statement from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = 'DasBenutzerSchema' and Table_Name like 'ErforderlicheEinschränkungFürBenötigteTeilmenge%'; Eventuell ginge es auch innerhalb einer Prozedur über Execute Immediate ( ![]() |
AW: Trigger auf Datenbankebene?
|
AW: Trigger auf Datenbankebene?
Interessant, dann würde ich wohl eher den offiziellen Limitations folgen, als dem Nachdruck eines SQL 99 Buches von dem auf der Seite geschrieben steht:
Zitat:
|
AW: Trigger auf Datenbankebene?
Die beiden Seiten
![]() ![]() Ok, wenn man weiterliest: Der zweite Link bezieht sich auf den SQL-99-Standard. Das dort beschriebene muss nicht zwingend mit MariaDB funktionieren. Hiernach scheint es aber ab MariaDB 10.2.3 zu funktionieren: ![]() Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz