Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Feldänderugnen im Trigger Prüfen Firebird (https://www.delphipraxis.net/112189-feldaenderugnen-im-trigger-pruefen-firebird.html)

Pro_RJ 16. Apr 2008 14:02

Datenbank: FireBird • Version: 2.0 • Zugriff über: IBexpert

Feldänderugnen im Trigger Prüfen Firebird
 
Huhu,
Also ich habe folgende Aufgabe :
Ich habe eine Tabelle Adressen wo ich pro User Adressen Speichern und verwalten kann.

Es sollen mehrere User den gleichen Adressstamm nutzen möchten.
Bsp.: User 1,2,3.
Wenn jetzt der User1 eine Adresse anlegt
AdressNr = 1,
Name1 = 'aaaa'
Vorname = 'bbbbb'.....

soll automatisch auf User2 und User3 die gleiche Adresse mit gleicher Adressnr,Vorname,name1..... angelegt werden.
So bis hierher kein Problem. :wink:

Wenn jetzt der User2 Name1 ändert, soll auch Automatisch der Name1 auf den User1 und User3 geändert werden.

Jetzt die Interessante Frage wie kann man sowas realisieren :?:
Ich hatte 2 grundsätzliche Überlegungen :
1. in Echtzeit über einen After Update Trigger like
Code:
 
  if (Old.Name1 <> New.Name1) then Update Adressen set Name1 = New.Name1 where AdressNr = New.AdressNr and ID <> New.ID;
  if (Old.Name2 <> New.Name2) then Update Adressen set Name2 = New.Name2 where AdressNr = New.AdressNr and ID <> New.ID;
Das Problem ist, das die Tabelle aus ca. 100 Feldern besteht die alle überwacht werden sollen.
Wenn ich den Trigger über den Beschriebenen weg aufbaue wir der Trigger Riesig und unüberwachbar und vor allem nicht pflegbar.
Denn wenn jetzt ein neues Feld hinzu kommt muss ich daran denken es in diesen Trigger mit einzupflegen.

Meine 2.Überlegung wäre eine Gleichschaltung ca alle 5 min.
Dafür müsste ich mir aber irgendwie speichern, welches Feld auf welchem User jetzt aktuell ist.
Was an sich ja über eine Tabelle sehr einfach zu realisieren wäre.
das Problem ist, der Trigger auch wieder so aussehen würde.
Code:
 
  if (Old.Name1 <> New.Name1) then execute procedure SetzeAenderunfskKZ('Name1',New.Zaehler);
  if (Old.Name2 <> New.Name2) then execute procedure SetzeAenderunfskKZ('Name2',New.Zaehler);
....
nur hier bin ich wieder an gleich Problem wie oben :-(

gibt es eine Möglichkeit einen Trigger nach folgendem Muster aufzubauen.

Code:
declare variable FLDName VarChar(25);
begin
  For
  Select RF.RDB$Field_Name
  from RDB$Relation_FIelds RF
  where Upper(RF.RDB$Relation_Name) = 'ADRESSEN'
  into :FLDName
  do
  Begin
    if (Old.FLDName <> New.FLDName) then execute procedure SetzeAenderunfskKZ(:FLDName,New.Zaehler);
  end
end
nur geht sowas überhabt?
Bzw. wie würdet ihr dieses Problem angehen?

mfg Jens

mkinzler 16. Apr 2008 14:05

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Man könnte auch für jedes Feld einen Trigger anlegen.
Eine Normalisierung des Schemas wäre aber auch ratsam.

Pro_RJ 16. Apr 2008 14:10

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Naja dann habe ich ja wieder das gleich Problem.
An der Datenbankstruktur kann ich leider nicht wirklich was ändern, da diese fest vorgegeben ist.

mkinzler 16. Apr 2008 14:15

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Zitat:

Naja dann habe ich ja wieder das gleich Problem.
Wäre aber übersichtlicher.

dfried 16. Apr 2008 14:15

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Ich verstehe den Sinn der ganzen Aktion noch nicht ganz, da durch diese Trigger eh alle User nachher alle Adresen gleich haben wieso dann die Adressen mehrfach (pro User) speichern?
Oder gibt es auch Konstellationen in denen ein USer explizit verhindern kann, dass die von Ihm eingegebene Adresse auch alle anderen User automatisch (über den Trigger) bekommen?

hoika 16. Apr 2008 14:19

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Hallo,

schreib dir doch eine Routine,
die den "unübersichtlichen" Trigger selber erzeugt,
indem die Tabelle analysiert wird (Feldnamen).

Die Methode rufst du auf, nachdem neue Felder erzeugt worden sind.


Heiko

Pro_RJ 16. Apr 2008 14:20

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Also das Programm und die Datenbank sind so entwickelt das jeder User ganz für sich alleine arbeitet.
Jetzt ist ein Anwender dazu gekommen, der zwar mit meheren Usern aberbeitet aber einen einheitlichen Adresstamm haben möchte.
Da es aufwändiger ist das gesamte Programm umzubauen wollte ich es über diesen weg realisieren.

mkinzler 16. Apr 2008 14:23

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Oder normalisiere die Tabellen und simuliere das Excel-Datenbank-Schema per View/SP

Pro_RJ 16. Apr 2008 14:30

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Ich darf aber weder an der Datenbankstruktur noch an Statements im Programm etwas ändern.
Im Prinzip darf ich nur die Daten duplezieren.

dfried 16. Apr 2008 14:35

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Würde wie mkinzler das vorschlägt die Tabelle durch einen gleichnamigen View ersetzen (die Tabelle natürlich vorher umenennen), dann ist das für das Programm transparent, d.h. es bekommt von der Änderung gar nix mit. Schwierig wird allerdings das Insert bzw. Update der Daten, da der View vermutlich nicht aupdatefähig sein wird.
Unter Oracle würde ich das über einen "Instead of"-Trigger realisieren, weiss jetzt aber leider nicht auswendig, ob Firebird das auch kann.

Pro_RJ 16. Apr 2008 14:37

Re: Feldänderugnen im Trigger Prüfen Firebird
 
gibt es keine möglichkeit das über eine schleife zu lösen?

in etwar so?
SQL-Code:
declare variable FLDName VarChar(25);
begin
  For
  Select RF.RDB$Field_Name
  from RDB$Relation_FIelds RF
  where Upper(RF.RDB$Relation_Name) = 'ADRESSEN'
  into :FLDName
  do
  Begin
    if (Old.FLDName <> New.FLDName) then execute procedure SetzeAenderungskKZ(:FLDName,New.Zaehler);
  end
end

mkinzler 16. Apr 2008 14:41

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Du müsstest dir dann das Statement manuell im trigger aufbauen lassen. Ich vermute allerdings dass dann die Performance vollends flöten ist.

Pro_RJ 16. Apr 2008 14:44

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Ich dachte es in etwa so:
Die StoredProc "SetzeAenderungskKZ" speichert das Feld, welches sich geändert hat in einer extra Tabelle ab.
Ein Timer geht alle 5 min diese Tabelle durch und stellt alle Datensätze aller User wieder gleich.

mkinzler 16. Apr 2008 15:02

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Du könntest, wie schon erwähnt die abfrage im Trigger dynamisch zusammenbauen und dann ausführen.

SQL-Code:
<schleife>
  sql = sql || ...
</schleife>
EXECUTE STATEMENT sql

Pro_RJ 16. Apr 2008 15:05

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Naja ich wollte ja im Trigger die "Old" und die "New" Werte vergleichen,damit ich nur die speichere, die Sich geändert haben.

RavenIV 16. Apr 2008 16:16

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Du kannst auch die IBObjects verwenden, da können die visuellen Komponenten die Änderung des Datensatzes farblich darstellen.

Pro_RJ 16. Apr 2008 17:44

Re: Feldänderugnen im Trigger Prüfen Firebird
 
naja ich wollte es ja am liebsten auf Datenbankebene machen.

alex517 16. Apr 2008 20:35

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Hallo Jens,

Wenn die Adressen sowieso immer identisch sein sollen, dann spielt es keine doch keine
Rolle ob du nur die geänderten Felder oder gleich alle synchronisierst.
Dafür sparst du dir aber der Vergleich und den Zusammenbau der SQL alles was mit
dem "Execute Statement" zusammenhängt.
Allerdings würde ich auf keinen Fall diese Methode wählen.
Statt dessen würde ich wie bereits von dfried vorgeschlagen eine View verwenden.
Selbstverständlich kann auch eine View mit Trigger updatefähig gemacht werden.

Kleines Beispiel:


SQL-Code:
/******************************************************************************/
/****         Generated by IBExpert 2007.12.08 16.04.2008 21:29:04         ****/
/******************************************************************************/

SET SQL DIALECT 3;

SET NAMES ISO8859_1;

SET CLIENTLIB 'C:\Programme\Firebird\Firebird_2_0\bin\fbclient.dll';

CREATE DATABASE 'PRO1/60050:D:\Daten\TestDB\TESTDB1.FDB'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 8192
DEFAULT CHARACTER SET ISO8859_1;



/******************************************************************************/
/****                               Domains                               ****/
/******************************************************************************/

CREATE DOMAIN DOM_ID AS
INTEGER;

CREATE DOMAIN VCHAR30 AS
VARCHAR(30);



/******************************************************************************/
/****                              Generators                             ****/
/******************************************************************************/

CREATE GENERATOR GEN_ADRESSE_ID;
SET GENERATOR GEN_ADRESSE_ID TO 7;

CREATE GENERATOR GEN_BENUTZER_ID;
SET GENERATOR GEN_BENUTZER_ID TO 3;



/******************************************************************************/
/****                                Tables                               ****/
/******************************************************************************/



CREATE TABLE ADRESSE (
    ID       DOM_ID NOT NULL,
    NACHNAME VCHAR30,
    VORNAME  VCHAR30,
    STR      VCHAR30,
    PLZ      VCHAR30,
    ORT      VCHAR30
);

CREATE TABLE BENUTZER (
    ID           DOM_ID NOT NULL,
    BENUTZERNAME VCHAR30
);



/******************************************************************************/
/****                                Views                                ****/
/******************************************************************************/


/* View: ADRESSEN */
CREATE VIEW ADRESSEN(
    BENUTZER_ID,
    ADRESSE_ID,
    NACHNAME,
    VORNAME,
    STR,
    PLZ,
    ORT)
AS
SELECT
  B.ID,
  A.ID,
  A.NACHNAME,
  A.VORNAME,
  A.STR,
  A.PLZ,
  A.ORT
FROM
  BENUTZER B,
  ADRESSE A
;


INSERT INTO ADRESSE (ID, NACHNAME, VORNAME, STR, PLZ, ORT) VALUES (1, 'Walkes', 'Otto', 'Kleine Gasse', NULL, NULL);
INSERT INTO ADRESSE (ID, NACHNAME, VORNAME, STR, PLZ, ORT) VALUES (2, 'Schmidt', 'Heinz', NULL, NULL, NULL);
INSERT INTO ADRESSE (ID, NACHNAME, VORNAME, STR, PLZ, ORT) VALUES (3, 'Müller', 'Lieschen', NULL, NULL, NULL);
INSERT INTO ADRESSE (ID, NACHNAME, VORNAME, STR, PLZ, ORT) VALUES (4, 'Rübe', 'Kunibert', NULL, NULL, NULL);
INSERT INTO ADRESSE (ID, NACHNAME, VORNAME, STR, PLZ, ORT) VALUES (7, 'dddd', NULL, NULL, NULL, NULL);

COMMIT WORK;

INSERT INTO BENUTZER (ID, BENUTZERNAME) VALUES (1, 'User1');
INSERT INTO BENUTZER (ID, BENUTZERNAME) VALUES (2, 'User2');
INSERT INTO BENUTZER (ID, BENUTZERNAME) VALUES (3, 'User3');

COMMIT WORK;



/******************************************************************************/
/****                             Primary Keys                            ****/
/******************************************************************************/

ALTER TABLE ADRESSE ADD CONSTRAINT PK_ADRESSE PRIMARY KEY (ID);
ALTER TABLE BENUTZER ADD CONSTRAINT PK_BENUTZER PRIMARY KEY (ID);


/******************************************************************************/
/****                               Triggers                              ****/
/******************************************************************************/


SET TERM ^ ;


/******************************************************************************/
/****                     Triggers for updatable views                    ****/
/******************************************************************************/

ALTER TRIGGER ADRESSEN_AIUD0
AS
BEGIN
  POST_EVENT 'ADRESSEN_CHANGE';
END
^

ALTER TRIGGER ADRESSEN_BIUD0
AS
begin
  if ((INSERTING) or (UPDATING)) then
  BEGIN
    IF (EXISTS(SELECT ID FROM ADRESSE WHERE (ID = NEW.ADRESSE_ID))) THEN
      UPDATE ADRESSE
      SET
        NACHNAME = NEW.NACHNAME,
        VORNAME = NEW.VORNAME,
        STR = NEW.STR,
        PLZ = NEW.PLZ,
        ORT = NEW.ORT
      WHERE (ID = NEW.ADRESSE_ID);
    ELSE
      INSERT INTO ADRESSE (
        ID,
        NACHNAME,
        VORNAME,
        STR,
        PLZ,
        ORT)
      VALUES (
        NEW.ADRESSE_ID,
        NEW.NACHNAME,
        NEW.VORNAME,
        NEW.STR,
        NEW.PLZ,
        NEW.ORT);
  END
  if (DELETING) then
  BEGIN
    DELETE FROM ADRESSE
    WHERE (ID = OLD.ADRESSE_ID);
  END
end
^

/******************************************************************************/
/****                         Triggers for tables                         ****/
/******************************************************************************/



/* Trigger: ADRESSE_BI */
CREATE TRIGGER ADRESSE_BI FOR ADRESSE
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
    NEW.ID = GEN_ID(GEN_ADRESSE_ID,1);
END
^

/* Trigger: BENUTZER_BI */
CREATE TRIGGER BENUTZER_BI FOR BENUTZER
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
    NEW.ID = GEN_ID(GEN_BENUTZER_ID,1);
END
^

SET TERM ; ^
alex

Pro_RJ 17. Apr 2008 08:59

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Morsche, :-D

Danke erstmal für die Hilfreichen Tipps.

Ich werde mir den Trigger doch per Schleife erzeugen und dann manuell Synchronisieren.
Die Idee mit dem View ist sehr gut aber dann hätte der User, für den das gedacht ist, eine einzelne Datenbank und eine komplett eigene Progrmmversion.
Das heist er ist nicht mehr über die "normale" Programmpflege wartbar.Sondern es müssten sämtliche Updates für seine Programmversion extra zurecht gemacht werden. Das ist schlicht und ergreifend nicht Pflegbar.

Deshalb muss ich leider die schlechtere Variant nutzen.Aber damit hat wieder jeder User das gleiche Programm und den gleichen Datenbankaufbau.

Wenn ihr noch Ideeen habt wie ich den Trigger einfacher aufbauen und pflegen kann wäre ich euch sehr dankebar.


mfg Jens

mkinzler 17. Apr 2008 09:01

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Nein, wenn der View heisst wie die Tabelle vorher hies, müssen am Programm keine Änderungen gemacht werden!

Pro_RJ 17. Apr 2008 09:17

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Ja das ist richtig.
Aber dafür müsste das Datenbankdesign für diesen einzelnen Kunden speziell angepasst werden.
Unsere Philosophie ist eigentlich jeder Kunde bekommt das gleiche Datenbankdesign und das gleiche Programm. Alle "Spezialanpassungen" für die einzelnen Kunden werden zentral vom Programm gesteuert.So das ob wohl jeder Kunde eigene Anpassungen hat nutzen alle exakt das gleiche.

mkinzler 17. Apr 2008 09:21

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Vielleicht wäre die normalisierte Db eine Option für alle Kunden.

Pro_RJ 17. Apr 2008 09:40

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Ja ist auch richtig.
Nur ein Paar Eckdaten :
ca: 100 Tabellen
3500 Felder
fast 500.000 Zeile QuellCode.

Pro : - Geschwindigkeitssteigerung
- geringere Datenbankgröße

Kontra : - ein riesen Umbau des Quelltextes.
- Änderung von alle Auswertungen/Druckformularen
- auf Grund der emormen Änderungen eine extrem große Fehleranfälligkeit.
- Es müsste per Update bei sämtlichen Kunden die Datenbank vom Programm aus neu Aufgebaut werden und dabei dürfen keinerlei Einstellungen,
Daten verlohren gehen
- Es wäre ein Riesen Kosten und Zeit aufwand.

Das Problem ist das die Datenbank seit nun mehr als 8 Jahren gepflegt und erweitert wird.
Wenn man jetzt an einem neuen Programm mit neuer Datenbank arbeitet bin auch absolut dafür sich vorher gedanken über das Datenbankdesign zu machen.
Und diese Datenbank soweit wie möglich zu normalisieren.
Nur ein bestehndes Programm mit bestehenden Datenbank nachträglich zu ändern ist annähern un möglich.Da dies einer Neuentwicklung gleich kommt.
Das ist auch der Grund dafür das ich an der Datenbank selber nicht viel machen kann.Bzw. sie nicht so Grundlegend ändern kann/darf.

alex517 17. Apr 2008 10:46

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Liste der Anhänge anzeigen (Anzahl: 1)
Normalisierung wäre eigentlich der richtige Weg..
Ich hätte aber noch eine View-Variante die über einen Generator (OPT$USER) umschaltbar ist.

alex

Pro_RJ 17. Apr 2008 11:03

Re: Feldänderugnen im Trigger Prüfen Firebird
 
Dankeschöööön ,
ich probiere es glich mal aus


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:16 Uhr.

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