Announcement

Collapse
No announcement yet.

Fragen zu Trigger

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

  • Fragen zu Trigger

    Frage 1:

    kann ich in einem Trigger Daten in ein Feld schreiben,
    die aus zwei anderen Feldern bestehen? Es soll folgendes
    umgesetzt werden.

    In einer Artikel-Datenbank besteht das Feld Artikel-Nr aus dem
    Herstellerkürzel char(3) (z.B. "MA-")welches seperat in einer
    anderen Tabelle geführt wird; und einer fortlaufenden Nr.
    vom Typ Integer (Autozählfeld ermittelt über Trigger)!

    Als ergebnis soll im Feld Artikel-Nr. dann "MA-123456" stehen.

    Wie muß der Trigger aussehen, der den Zugriff auf eine andere
    Tabelle hat um die Herstellerbezeichnung zu ermitteln und dann
    mit einer lfdnr-nr versehen wird (kombinantion aus Char und Integer)

    Frage 2:
    Ich aktualisiere Daten (Artikelstamm der Hersteller) via TBatchMove, und überprüfe auch ob Daten in der Quelltabelle gelöscht wurden um diese dann auch aus der Zieltabelle zu entfernen! Es handelt sich wie o. beschrieben um eine Artikeldatenbank. Es dürfen aber nur Artikel gelöscht werden,
    die keinen Bestand haben.

    Kann man den DELETE-Vorgang abbrechen, wenn man in einem TRIGGER BEFORE
    DELETE prüft ob Bestände vorhanden sind? Der Datensatz soll dan nicht
    gelöscht werden, sondern es soll ein Flag (Restbestand) gesetzt werden.

    Wenn mir jemand mit Beispiel weiterhelfen kann wäre ich dankbar.

    Besten Dank!

  • #2
    Hallo,<p>
    zu Frage 1: Ich nehme 'mal an, dass das Herstellerkürzel in der Herstellertabelle und die Artikel-ID in der Artikeltabelle gespeichert ist. Wenn dem so ist, könnte mann doch in der Select-Anweisung ein berechnetes Feld einfügen, z.B.:<br>
    <code> select h.kuerzel || a.id as completeartikelid from hersteller h, artikel a where (h.id = a.herstellerid)</code><br>Bei einem extra in der Artikeltabelle mitgeführtem Feld entstehen doch redundante Daten.<p>
    zu Frage 2: Ich vermute, dass das Löschen eines Artikels von der Client-Anwendung ausgelöst wird, wenn der Nutzer einen Button klickt oder so. In dem Falle würde ich keinen Trigger sondern eine stored procedure verwenden, in welcher der Löschvorgang erst nach einer Prüfung stattfindet oder eben das Flag gesetzt wird.<p>
    Best Regards<br>Wolfhar

    Comment


    • #3
      Ja, das Löschen wird von der Client-Anwendung ausgelöst
      aber via TBatchMove ...und dem Client ist nicht bekannt
      wann das Löschen expliziet ausgelöst wird.

      Das gleiche gilt für die Aktualisierung der Daten. Es soll
      halt beim Append aus TBatchMove herraus die eigene
      Artikel-Nr. generiert werden. Die aus Hersteller Kürzel
      und lfdNr. Besteht.

      Vielleicht gibt noch eine andere Lösung. Aber Trotzdem besten
      Dan

      Comment


      • #4
        Hallo,

        die Stored Procedure kann auch direkt aus dem Trigger heraus aufgerufen werden. Über die SQL-Kontextvariablen OLD und NEW hat der Trigger direkt den vollen Zugriff auf die "alten" bzw. "neuen" Daten, die durch die INSERT-, UPDATE- oder DELETE-Anweisung entstehen.

        Im Ordner <i>Delphi | IBX | RedSys</i> wird eine IBX-Beispielanwendung vorgestellt, die u.a. einen Trigger mit einer Stored Procedure kombiniert:
        <pre>
        CREATE TRIGGER BEITRAGTERMINID FOR BEITRAG BEFORE INSERT AS
        BEGIN
        IF (NEW.TERMINNR IS NULL) THEN NEW.TERMINNR = GEN_ID(GEN_TERMINID,1);
        IF (NEW.TERMINWARNUNG IS NULL) THEN NEW.TERMINWARNUNG = 'N';
        EXECUTE PROCEDURE INSERTBELEG NEW.AUSGABEID, NEW.MANUSKRIPTID;
        END
        ^
        CREATE PROCEDURE InsertBeleg (iAusgabeID INTEGER, iManuskriptID INTEGER)
        AS
        DECLARE VARIABLE sAbo CHAR(1);
        DECLARE VARIABLE iAutor INTEGER;
        DECLARE VARIABLE iCount INTEGER;
        BEGIN
        SELECT a.IstAbonnent, a.AUTORID
        FROM Autor a JOIN Manuskript m ON a.AUTORID = m.AUTORID
        WHERE m.ManuskriptID = :iManuskriptID
        INTO :sAbo,:iAutor;
        /* Ein Abonennt bekommt kein Belegexemplar */
        IF (:sAbo = 'N') THEN
        BEGIN
        /* AutorID fuer diese AusgabeID bereits vorhanden? */
        SELECT COUNT(*)
        FROM BELEG
        WHERE AUSGABEID = :iAusgabeID AND AUTORID = :iAutor
        INTO :iCount;
        IF (:iCount = 0) THEN
        BEGIN
        /* Neuen Datensatz in BELEG anlegen */
        INSERT INTO BELEG (BELEGID,AUSGABEID,AUTORID,GRUND)
        VALUES (GEN_ID(GEN_BELEGID,1),:iAusgabeID,:iAutor,'Artike l-Autor');
        END
        END
        END
        ^
        </pre&gt

        Comment


        • #5
          Hallo Herr Kosch,
          ich habe versucht das o.a. Beispiel aus dem RedSys Porjekt
          nachzuvollzeihen. Grundsätzlich kein Problem. Mir ist nur
          nicht ganz klar, wie ich mit den Parametern umgehen soll.

          Ich habe eine Tabelle, in der Prozentwerte für Preisaufschläge
          enthalten sind von verschiedenen Lieferanten (ImportFilter). Diese möchte verwenden um in der Artikeldatei die Verkaufspreise zu berechnen (VK1=EK+Preisaufschlag1 ...) usw.

          Ich möchte in einer Stored Procedure die berechnungen für die
          Verkaufspreise machen.

          Ich benutze eine TBatchMove-Componente um die Daten von verschiedenen
          Quelltabellen in eine Zietabelle (Artikelstamm) zu kopieren bzw. zuüberschreiben. Ich benutze Trigger um ein Flag zu setzen, wenn Daten neu hinzugekommen bzw. geändert wurden.

          CREATE PROCEDURE PUpdate (P1 INTEGER, P2 INTEGER)
          begin
          update artikel set
          VK1=EK+:P1, VK2=EK+P2;
          end;

          Die Syntax für den Aufruf im Trigger ist mir auch klar, nur
          wie kann ich die Werte für die Parameter P1, P2 usw. setzen die
          ja aus der FilterTabelle kommen. Wo muß ich die Parameter definieren?

          Dann hätte ich noch ein anderes kleineres Problem: Ich möchte
          aus einen Parameter Typ Char und einem Feldwert LfdNR TypInteger
          den Inhalt eines anderen Feldes Typ Char festlegen. Beispiel

          Parameter: Kuezel ('MA-') und LFDNR 9890 soll 'MA-9890' werden

          CREATE PROCEDURE SetArtikelNr (Kuerzel Char(3))
          begin
          update artikel set
          NeueArtikelNr=:Kuerzel+IntToStr(LFDNR);
          end;

          Wenn ich das so mache bekomme ich eine Fehlermeldung
          Parameter Kuerzel nicht bekannt. Kann man keine Werte
          unterschiedlichen Typs kombinieren?

          Vielen Dank für Ihre Hilf

          Comment


          • #6
            Hallo,

            die Frage nach den Parametern verstehe ich nicht. In meinem Beispiel hat die aus dem Trigger heraus aufgerufene Stored Procedure ja auch zwei Parameter, die im Trigger über die SQL-Kontextvariablen <b>NEW.<i>xyz</i></b> mit Werten gefüllt werden. Man kann jedoch innerhalb der Stored Procedure andere Daten, die im Kontext des Triggers nicht sichtbar sind, über SELECT vorher gezielt abholen.

            Auch das zweite Problem kann ich nicht nachvollziehen. Angenommen, die Tabelle <i>Artikel</i> hat die folgende Struktur:
            <pre>
            CREATE TABLE artikel (
            ID INTEGER NOT NULL PRIMARY KEY,
            LFDNR INTEGER,
            NeueArtikelNr VARCHAR(10),
            VK1 DECIMAL(10,2),
            VK2 DECIMAL(10,2))
            </pre>
            Die Stored Procedure soll nun die Spalte <i>NeueArtikelNr</i> ausfüllen, wobei an das als Parameter übergebene Kürzel der INTEGER-Wert aus der Spalte LFDNR angehängt wird:
            <pre>
            CREATE PROCEDURE SetArtikelNr(Kuerzel CHAR(3)) AS
            BEGIN
            UPDATE artikel
            SET NeueArtikelNr = :Kuerzel || LFDNR;
            END
            ^
            </pre>
            Wird das Ganze ausgeführt, so ist das gewünschte Ergebnis in der Spalte <i>NeueArtikelNr</i> zu finden:
            <pre>
            EXECUTE PROCEDURE SetArtikelNr('ABC')
            </pre>
            Die Stored Procedure konnte durch den Verkettungs-Operator II den CHAR-Wert mit dem INTEGER-Wert verbinden, da der InterBase die Typumwandlung implizit vornimmt. Man könnte aber auch direkt zu CAST greifen, um die Typumwandlung explizit festzulegen:
            <pre>
            SELECT CAST(LFDNR AS VARCHAR(5)) || VK1 FROM artikel
            </pre&gt

            Comment


            • #7
              Vielen Dank, daß mit den Parametern funktioniert! Ich hätte nun
              nochmal folgende Frage:
              Ich übertrage Daten von einer Quell-Tabelle in eine Ziel-Tabelle
              und verwende dazu die TBatchMove Komponente, klappt hervorragent!

              Kann man während des Updatevorgang auf die Ereignisse der Zieltabelle reagieren, ich meine z.B. auf das BeforePost? Damit man z.B. Parameter
              an eine StoredProcedure übergeben kann.

              Dank

              Comment

              Working...
              X