Announcement

Collapse
No announcement yet.

Trigger zum Tabellenabgleich

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Trigger zum Tabellenabgleich

    Ich habe ein großes Problem mit Triggern unter Oracle. Meine Anwendung hat zwei einfache Straßentabellen [ID (integer, primary key),Name (varchar50), Kürzel (varchar12)], nach jeder Eingabe bzw. Änderung sollen die beiden Tabellen über Trigger abgeglichen werden. Leider bekomme ich immer die Fehler ORA-06512 und ORA-04088.

    Der Quellcode der beiden Trigger lautet:

    <PRE>
    CREATE OR REPLACE TRIGGER "TEST".IACABGLEICH_RHQSR_RHSTR after INSERT on RHQSTR
    for each row
    DECLARE anz INTEGER;id INTEGER;
    BEGIN
    SELECT MAX(STR_ID) INTO id from RHSTR;
    id:=id+1;
    SELECT COUNT(*) INTO anz FROM RHSTR where STR_KUERZEL = :new.QSR_KUERZEL;
    if anz=0 then
    INSERT INTO RHSTR (STR_ID,STR_NAME,STR_KUERZEL) VALUES (id,:new.QSR_NAME,:new.QSR_KUERZEL);
    elsif anz>0 then
    if :new.QSR_NAME <> ld.QSR_NAME then
    UPDATE RHSTR SET STR_NAME = :new.QSR_NAME WHERE STR_KUERZEL = :new.QSR_KUERZEL;
    end if;
    end if;
    END;
    /
    CREATE OR REPLACE TRIGGER "TEST".IACABGLEICH_RHSTR_RHQSR after INSERT on RHSTR
    for each row
    DECLARE anz INTEGER;id INTEGER;
    BEGIN
    SELECT MAX(QSR_ID) INTO id from RHQSTR;
    id:=id+1;
    SELECT COUNT(*) INTO anz FROM RHQSTR where QSR_KUERZEL = :new.STR_KUERZEL;
    if anz=0 then
    INSERT INTO RHQSTR (QSR_ID,QSR_NAME,QSR_KUERZEL) VALUES (id,:new.STR_NAME,:new.STR_KUERZEL);
    elsif anz>0 then
    if ld.STR_NAME <> :new.STR_NAME then
    UPDATE RHQSTR SET QSR_NAME = :new.STR_NAME WHERE QSR_KUERZEL = :new.STR_KUERZEL;
    end if;
    end if;
    END;
    /

    </PRE>

    Vielen Dank für Eure Tipps.

    Roland

  • #2
    erstmal heißt es, wenn auch beim bearbeiten (update) etwas überprüft werden soll <BR><BR>
    CREATE OR REPLACE TRIGGER "TEST".IACABGLEICH_RHQSR_RHSTR after insert <B>or Update</B> on RHQSTR
    <BR>
    <BR>
    begin<BR>
    -- damit fängen sie die art der manupulation ab<BR>
    if inserting or ... then ... end if;<BR>
    if updating or ... then ... end if;<BR>
    end

    Comment


    • #3
      Hallo Roland,

      was du da mit den beiden Triggern machst sieht gefährlich aus. Wenn ich es auf die Schnelle übeblicke, dann rufen sie sich gegenseitig auf: IACABGLEICH_RHQSR_RHSTR macht bedingt ein INSERT INTO RHSTR, welches wiederum IACABGLEICH_RHSTR_RHQSR zündet, der dann u.U. ein INSERT INTO RHQSTR macht, was wiederum IACABGLEICH_RHQSR_RHSTR zündet ... usw.

      Es gibt unter ORACLE auch noch einige Bedingungen für Trigger. So z.B. diese, das ein Trigger <b>nicht</b> die gerade manipulierte Tabelle abfragen darf. Aber genau das passiert (neben der möglichen Rekursion) durch die beiden Trigger. IACABGLEICH_RHQSR_RHSTR löst ja u.U. IACABGLEICH_RHSTR_RHQSR aus und als erste Anweisung kommt ein SELECT MAX(QSR_ID) INTO id from RHQSTR; und das ist dann lt. ORACLE-Spezifikation unzulässig.

      Gruß Fal
      Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

      Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

      Comment


      • #4
        Hallo Falk,

        das das Ganze gefährlich ist, sehe ich auch so.
        Die ewigen Rekursionen dürften nicht auftreten, da ja über das Feld Kürzel abgeglichen wird, d.h. eine neue Straße in STR wird auch in QSTR eingetragen mit dem identischen Kürzel. In STR wird dies nicht passieren, da ja dieses Kürzel schon existiert.

        Zum zweiten Teil gebe ich Dir recht und weiß keine genaue Lösung.

        Danke

        Rolan

        Comment


        • #5
          Hallo Roland,

          Für deinen Abgleich gibt es nach meiner Ansicht 3 Möglichkeiten, wovon die Triggervariante sicherlich die schlechteste ist. Meine Alternativvorschläge wären:
          <p>1. Du verwendest generell nur eine Funktion zum Einfügen und Ändern von Daten, die beide Tabellen analog bedient. Nachteil: es dürfen keine "direkten" Inserts in eine der beiden Tabellen gemacht werden.</p>
          <p>2. Du erstellst eine View als "Mischung" der beiden Tabellen und versiehst diese mit einem INSTEAD OF-Trigger. Direkte Datenmanipulationen dürfen dann nur auf diese View stattfinden. Der INSTEAD OF-Trigger "verteilt" dann die Daten via INSERT, bzw. UPDATE auf beide Tabellen.</p>
          <p>3. 2 wechselseitige Trigger (wie von dir praktiziert), nur das ich beide Tabellen um ein zusätzliches Feld, z.B "FROM_TRIGGER" NUMBER(1), ergänzen würde. Dieses Feld wird nur bei einem INSERT INTO innerhalb des Triggers mit z.B. "1" belegt und bleibt bei "normalen" Inserts NULL. Damit hat der jeweils andere Trigger die Chance anhand von "if :NEW.FROM_TRIGGER = 1 then MacheNichts"
          zu entscheiden, ob der Aufruf aus der Applikation kommt und er die andere Tabelle mit anpassen muß (und kann), oder ob er gerade von dem anderen Trigger ausgelöst wurde und jetzt besser nichts macht.</p>

          Aber wie gesagt ich würde eine der Varianten 1 oder 2 bevorzugen.

          Gruß Fal
          Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

          Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

          Comment


          • #6
            hallo roland,

            ich schätze du hast noch eine vierte variante zur auswahl:

            das problem mit dem zugriff tritt nur in row level triggern auf. du könntest also ein package schreiben, dass in den row level triggern die daten sammelt und in einem statement level trigger die verarbeitung vornimmt.

            ich würde allerdings falks lösung no 2 vorziehen. um die auswirkung auf die applikation klein zu halten würde ich die beiden tabellen umbenamsen und views mit den originalnamen erstellen.

            gruss volke

            Comment


            • #7
              Hallo Falk, Hallo Volker,

              vielen Dank für die Tipps! Ich werde zuerst mal Variante 1 realisieren. Ich denke, da bin ich am schnellsten mit der Umsetzung. Die anderen beiden Varianten werde ich versuchen, wenn mal Zeit zum Testen ist :-)

              Danke

              Rolan

              Comment


              • #8
                Hallo, warum machst du das nicht über eine simple MASTER / MASTER Replikation ?<BR>
                Die übernimmmt alle deine Probleme!<BR>
                <BR>
                Gruß<BR>
                Matthias<BR&gt

                Comment


                • #9
                  Hallo, Eigentlich ganz einfach, in jeder Tabelle muss ein eindeutiges Feld exsistieren, damit die Trigger sich nicht rekrusiv aufrufen.<BR>
                  Bsp.:<BR>
                  <BR>
                  TABELLE1: KEY, NAME, KUERZEL, TABELLEN_NAME<BR>
                  TABELLE2: KEY, NAME, KUERZEL, TABELLEN_NAME<BR>
                  <BR>
                  in Taballe 1 wird Default immer z.B eine 1 eingetragen, in Tabelle 2 immer eine 2.<BR>
                  Nun die Trigger auf das before Insert Ereignis<BR>
                  CREATE TRIGGER ... ON TABELLE1 BEFORE INSERT...<BR>
                  OLD AS OLD_INS NEW AS NEW_INS FOR EACH ROW<BR>
                  BEGIN<BR>
                  IF :new_ins.TABELLEN_NAME = 1 THEN
                  BEGIN<BR>
                  INSERT INTO TABLELLE 2 VALUES (:new_ins.key, ...., :new_Ins.TABLLEN_NAME);<BR>
                  END<BR>
                  END IF<BR>
                  <BR>
                  auf die Tabelle das gleiche, allerdings mit Abfrage ob eine 2 drin ist.<BR>
                  Beim einfügen in die Tabelle 1 wird zwar der Trigger auf die Tabelle 2 gestartet, aber er macht nichts mehr.<BR>
                  <BR>
                  Beim Update machts du das gleiche, aber du fragst :OLD Werte ab!<BR>

                  Gruss Matthias<BR&gt

                  Comment


                  • #10
                    hallo matthias,

                    deine lösung hat im updatefall imho ein kleines problem.

                    frage ich den old-wert ab, dann funzt die replikation nur wenn ich den update auf der gleichen tabelle mache wie den insert. ich könnte natürlich den new-wert abfragen, dann muss ich aber alle updates ändern und die tabellenkennung jedesmal setzen.

                    gruß volke

                    Comment


                    • #11
                      Hi Volker, ich habe das bisher nur mit Insert kurz gestestet.<BR>
                      Aber du hast Recht! <BR>
                      Also bleibt eigentlich nur Weg wie bei einer Replication übrig, separate Tabellen anlegen,
                      die die Inserts, Updates und Deletes sich merken.<BR>
                      Melde mich wenn ich die Lösung habe<BR>
                      Gruss Matthias<BR>
                      Danke für den Hinweis :-)))<BR&gt

                      Comment

                      Working...
                      X