![]() |
Datenbank: Interbase • Version: XE • Zugriff über: SQL
Änderungs-Logging, Eintragen beim Löschen mit Detail-Tabelle
Hi,
Ich möchte Änderungen an einer Tabelle in einer Interbase-DB über Trigger in einer Export-Tabelle erfassen um so eine Liste von zu exportierenden Datensätzen zu erstellen. Ich habe folgende Tabellen:
Code:
und folgende Trigger:
Export (
ID, SCHLUESSELFELDID, AENDERUNGSART VARCHAR(1), AENDERUNGSDATUM ); Kopf ( KOPF_ID Daten... ); PK: KOPF_ID
Code:
die jeweils einen Eintrag in die "Export"-Tabelle entsprechend der Änderungs-Art "I", "U", "D" vornehmen (In Echt noch etwas genauer, so dass nur Änderungen an bestimmten Feldern einen Eintrag auslösen).
Kopf_AI_EXPORT for Kopf active after insert;
Kopf_AU_EXPORT for Kopf active after update; Kopf_AD_EXPORT for Kopf active after delete; Das funktioniert für mich sehr gut. Ich habe so eine Tabelle, in der alle Änderungen (das es eine Änderung gab, nicht welche) protokolliert werden. Diese Tabelle wird abgearbeitet und daraus ein Export mittels einem weiteren Programm ausgelöst. Jetzt muss ich zusätzlich Änderungen an einer vom Kopf abhängigen Positions-Tabelle mit erfassen. Hierzu habe ich die Positions-Tabelle, einen "Foreigen Key" auf den Kopf und entsprechende Trigger angelegt:
Code:
Diese drei Trigger schreiben jetzt in die Export-Tabelle immer einen Eintrag mit der Änderungs-Art "U" für Update.
Detail (
DETAIL_ID, KOPF_ID, Daten... ); PK: DETAIL_ID FK: KOPF_ID -> Kopf.KOPF_ID on update cascade on delete cascade; Detail_AI_EXPORT for Detail active after insert; Detail_AU_EXPORT for Detail active after update; Detail_AD_EXPORT for Detail active after delete; Jedes Hinzufügen, Änderung an einem Positions-Datensatz oder Löschen einer Position ist ein "Update" des Kopfes. Das funktioniert bis auf einen Fall für mich korrekt: Wenn der Kopf-Datensatz gelöscht wird, dann löscht der "Foreign Key" der Detail-Tabelle die entsprechenden Datensätze. Die dadurch gelöschten Positionen schreiben einen "U"-Eintrag nach dem "D"-Eintrag des "Kopf_AD_EXPORT". Diese Datensätze können vom Export-Programm nicht Exportiert werden, da sie nicht mehr in der Kopf-Tabelle vorhanden sind. Auch eine Umstellung des "Detail_AD_EXPORT" auf "before delete" führt zum selben Ergebnis. Anscheinend ist hier die Reihenfolge bei Interbase folgende: Kopf.Delete ->Ich kann jetzt den "Foreigen Key" auf on update cascade on delete no action;ändern und einen "Kopf.BeforeDelete"-Trigger erstellen, der die abhängigen Datensätze in der Detail-Tabelle löscht. Dadurch würde die Reihenfolge passen. Das will ich aber eigentlich vermeiden, da der "cascade"-Aufruf so simple und gut funktioniert. Gibt es hierfür bessere Lösungen oder ein besseres Konzept? |
AW: Änderungs-Logging, Eintragen beim Löschen mit Detail-Tabelle
Protokollieren kannst du natürlich auch im BeforeDelete.
Sollte das Delete aus irgendeinem Grund fehlschlagen, wird auch dein Protokolleintrag wieder entfernt. Das System wird automatisch auf einen internen Savepoint zurückgesetzt, der vor dem Delete gesetzt wird. Du kannst also im BEFOREDELETE der Haupttabelle die Detaildatensätze einfach löschen und so die Detailtrigger auslösen. |
AW: Änderungs-Logging, Eintragen beim Löschen mit Detail-Tabelle
Hi,
das hilft mir aber nicht weiter oder ist das was ich eigentlich nicht will oder? es gibt 2 "Verschiedene" Löschungen aus der Detail-Tabelle:
Kann ich das ohne Umstellung des "on delete cascade;" Constraint erreichen? |
AW: Änderungs-Logging, Eintragen beim Löschen mit Detail-Tabelle
Frag doch im Trigger der Details bei einer Löschung, ob es den Eltern/Kopfeintrag noch gibt...
|
AW: Änderungs-Logging, Eintragen beim Löschen mit Detail-Tabelle
Ich habe das mal für MySQL 5.6 (TIMESTAMP mit Nachkommastellen) zusammengebaut inkl. eines kleinen Tests. Durch die Verwendung des
SQL-Code:
kann man im Trigger prüfen, ob es tatsächlich eine Änderung am Datensatz gegeben hat.
TIMESTAMP(6)
Wird nämlich eine Zeile mit identischen Werten aktualisiert, dann wird die
SQL-Code:
Spalte nicht aktualisiert, der Trigger wird trotzdem ausgelöst. Mit einem genauen
TIMESTAMP
SQL-Code:
kann nun im Trigger zuverlässig (genug :)) auf eine Änderung geprüft werden.
TIMESTAMP
Natürlich lösen die Detail-Löschung durch den Foreign-Key keine weiteren Log-Einträge aus -> siehe Trigger auf der Tabelle
SQL-Code:
. Das grundlegende Prinzip ist aber für jedes Datenbanksystem gleich ;)
detail
SQL-Code:
Hier ein kleiner Test ...
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for `master` -- ---------------------------- DROP TABLE IF EXISTS `master`; CREATE TABLE `master` ( `id` int(11) NOT NULL AUTO_INCREMENT, `updated` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `data` varchar(30) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `detail` -- ---------------------------- DROP TABLE IF EXISTS `detail`; CREATE TABLE `detail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `updated` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), `mastid` int(11) NOT NULL, `data` varchar(30) NOT NULL, PRIMARY KEY (`id`), KEY `mastid` (`mastid`), CONSTRAINT `setail_master` FOREIGN KEY (`mastid`) REFERENCES `master` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for `log` -- ---------------------------- DROP TABLE IF EXISTS `log`; CREATE TABLE `log` ( `tab` varchar(30) NOT NULL, `id` int(11) NOT NULL, `act` varchar(1) NOT NULL, `org` varchar(30) NOT NULL, `ocurred` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DELIMITER // -- ---------------------------- -- Triggers structure for table detail -- ---------------------------- CREATE TRIGGER `detail_AI` AFTER INSERT ON `detail` FOR EACH ROW BEGIN INSERT INTO log ( tab, id, act, org ) SELECT 'master', id, 'U', 'detail insert' FROM `master` WHERE id = NEW.mastid; END;// CREATE TRIGGER `detail_AU` AFTER UPDATE ON `detail` FOR EACH ROW BEGIN -- Ist wirklich etwas geändert worden? IF OLD.updated <> NEW.updated THEN -- Änderung für die ALTE Master-ID eintragen INSERT INTO log ( tab, id, act, org ) SELECT 'master', id, 'U', 'detail update' FROM `master` WHERE id = OLD.mastid; -- Hat sich die Master-ID geändert? IF OLD.mastid <> NEW.mastid THEN -- Änderung für die NEUE Master-ID eintragen INSERT INTO log ( tab, id, act, org ) SELECT 'master', id, 'U', 'detail update' FROM `master` WHERE id = NEW.mastid; END IF; END IF; END;// CREATE TRIGGER `detail_AD` AFTER DELETE ON `detail` FOR EACH ROW BEGIN INSERT INTO log ( tab, id, act, org ) SELECT 'master', id, 'U', 'detail delete' FROM `master` WHERE id = OLD.mastid; END;// -- ---------------------------- -- Triggers structure for table master -- ---------------------------- CREATE TRIGGER `master_AI` AFTER INSERT ON `master` FOR EACH ROW BEGIN INSERT INTO log ( tab, id, act, org ) VALUES ( 'master', NEW.id, 'I', 'master insert' ); END;// CREATE TRIGGER `master_AU` AFTER UPDATE ON `master` FOR EACH ROW BEGIN IF NEW.updated <> OLD.updated THEN IF NEW.ID = OLD.id THEN INSERT INTO log ( tab, id, act, org ) VALUES ( 'master', NEW.id, 'U', 'master update' ); ELSE INSERT INTO log ( tab, id, act, org ) VALUES ( 'master', OLD.id, 'D', 'master update' ), ( 'master', NEW.id, 'I', 'master update' ); END IF; END IF; END;// CREATE TRIGGER `master_AD` AFTER DELETE ON `master` FOR EACH ROW BEGIN INSERT INTO log ( tab, id, act, org ) VALUES ( 'master', OLD.id, 'D', 'master delete' ); END;// DELIMITER ; SET FOREIGN_KEY_CHECKS = 1;
SQL-Code:
... der dann folgendes LOG produziert
--
-- Test the structure -- -- Create some master records INSERT INTO `master` ( `data` ) VALUES ( 'master 1' ), ( 'master' ), ( 'master 3' ); -- 3 log entries -- Create some details INSERT INTO `detail` ( `mastid`, `data` ) VALUES ( 1, 'detail' ), ( 2, 'detail 2' ), ( 2, 'detail' ), ( 3, 'detail' ); -- 4 log entries -- Do some fake and real updates on master UPDATE `master` SET `data` = 'master 1' WHERE id = 1; -- no real update UPDATE `master` SET `data` = 'master 2' WHERE id = 2; -- real update UPDATE `master` SET `data` = 'master 3' WHERE id = 3; -- no real update -- 1 log entry ( for touching 3 records ) -- Do some fake and real updates on detail UPDATE `detail` SET `data` = 'detail 1' WHERE mastid = 1; -- 1 real update UPDATE `detail` SET `data` = 'detail 2' WHERE mastid = 2; -- 1 real update, 1 fake update -- 2 log entries (for touching 3 records ) -- switch the master of detail UPDATE `detail` SET `mastid` = 3 WHERE mastid = 1; -- 2 log entries ( for master 1 and master 3 ) -- delete a detail record DELETE FROM `detail` WHERE `data`='detail'; -- 1 log entry -- delete a master with details DELETE FROM `master` WHERE id = 2; -- 1 log entry
|
AW: Änderungs-Logging, Eintragen beim Löschen mit Detail-Tabelle
Hi,
Die Umsetzung von Zitat:
Zitat:
Select auf die Master-TabelleDanke. Besonders Sir Rufo für den kompletten Aufbau. Meine Struktur sah ähnlich aus. Ich habe bei mir nur die "Update ohne Änderung"-Prüfung und das Ändern des PKey weg gelassen. Der insert in die Log-Tabelle wurde nur direkt gemacht... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:38 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