M.: Mysql-Trigger macht doppelten Eintrag

Mahlzeit,

momentan hab ich ein Problem, das ich nicht verstehe. Ein Trigger arbeitet zwar richtig, macht aber zwei identische Einträge in der Zieldatenbank.

  
CREATE TRIGGER `stock_update`  
AFTER UPDATE  
ON `STOCKCURRENT` FOR EACH ROW  
BEGIN  
		IF (OLD.UNITS != NEW.UNITS) THEN  
			INSERT INTO TRIGGER_STOCK SET article=OLD.PRODUCT  
				, location=OLD.LOCATION  
				, action='update'  
				, old_stock=OLD.UNITS  
				, new_stock=NEW.UNITS;  
		END IF;  
	END  

mysql  Ver 14.14 Distrib 5.1.72, for debian-linux-gnu (x86_64) using readline 6.1

Kann das am Trigger liegen? Ich macht noch Tests im Mysql-Frontend, bisher hab ich nur mit meiner Software getestet. Wenn es aber evtl. ein Bug in Mysql ist, kann ich mir viel Arbeit beim Suchen sparen ;)

Kennt jemand diesen Effekt?

--
42
  1. Moin M.,

    doofe Frage, aber bist du sicher, dass du nicht aus Versehen zweimal diesen Trigger eingerichtet hast?

    momentan hab ich ein Problem, das ich nicht verstehe. Ein Trigger arbeitet zwar richtig, macht aber zwei identische Einträge in der Zieldatenbank.

    Wieviele Tuple wurden denn geändert? Lies doch mal affected rows aus.

    Kann das am Trigger liegen?

    Naja. Jain. Es kann am Trigger liegen, wenn mehrere Reihen betroffen sind (steht ja dran: FOR EACH ROW). Aber wenn der Trigger nur einmal ausgeführt wird sollte auch nur einmal ein INSERT stattfinden. Loopst ja nicht.

    LG,
     CK

    1. Mahlzeit,

      Moin M.,

      doofe Frage, aber bist du sicher, dass du nicht aus Versehen zweimal diesen Trigger eingerichtet hast?

      Zumindest wird er in Chive nur einmal angezeigt. Und im Dump steht bei jedem Table und jedem Trigger ein DROP IF EXISTS. Also gehe ich davon aus, er existiert nur einmal.

      momentan hab ich ein Problem, das ich nicht verstehe. Ein Trigger arbeitet zwar richtig, macht aber zwei identische Einträge in der Zieldatenbank.

      Wieviele Tuple wurden denn geändert? Lies doch mal affected rows aus.

      Stimmt, das kann ich machen. Hätte ich auch selber drauf kommen können. Wenn aber aus irgendeinem Grund das Statement nicht doppelt gesendet wird, kanns daran nicht liegen.
      Es handelt sich um eine Zeile mit ner absolut eindeutigen ID. Ist ein Kassensystem und hier speziell der Trigger, der eine Bestandsänderung mitloggt.

      Naja. Jain. Es kann am Trigger liegen, wenn mehrere Reihen betroffen sind (steht ja dran: FOR EACH ROW). Aber wenn der Trigger nur einmal ausgeführt wird sollte auch nur einmal ein INSERT stattfinden. Loopst ja nicht.

      Ich werd nochmal die Logs mitlaufen lassen. Es darf nur eine Reihe sein, maximal wird die doppelt geändert.

      Aber danke erstmal. Ich meld mich wieder, im besten Fall mit ner Erfolgsmeldung und ner Lösungsbeschreibung :)

      --
      42
    2. Mahlzeit,

      irgendwo kommt ich mir jetzt von meinem Server verarscht vor ......

        
      433 Query     UPDATE unicentaopos.STOCKCURRENT SET `UNITS`='200' WHERE PRODUCT="e106568f-4a3a-4c08-9a16-c64d618849a4" AND LOCATION="0"  
      433 Query     INSERT INTO TRIGGER_STOCK SET article=OLD.PRODUCT  
      433 Query     INSERT INTO TRIGGER_STOCK SET article=OLD.PRODUCT  
      
      

      Und dabei ist es völlig egal, ob ich das Query per Chive, PHPMyAdmin oder meiner Software absetze.
      Im Mysql-Client greift der Trigger gar nicht, aber ich vermute, das ist die Einschränkung, die in der Doku steht.

      Und der Trigger existiert definitiv nur einmal. Ich werd weitersuchen, aber vielleicht fällt dir oder jemand anderem noch was ein :)

      --
      42
      1. Mahlzeit,

        ich sterbe gleich ......
        Grundsätzlich darf es in der Tabelle mit dem Bestand jeder Artikel blos einmal pro Lagernummer auftauschen. Trotzdem steht genau der Artikel, mit dem ich teste, doppelt drin.
        Und da ich damit nicht gerechnet hab, hab ichs nicht geprüft.

        Ok, Betriebsblind aber den Fehler gefunden ;)

        --
        42
        1. Moin M.,

          Grundsätzlich darf es in der Tabelle mit dem Bestand jeder Artikel blos einmal pro Lagernummer auftauschen. Trotzdem steht genau der Artikel, mit dem ich teste, doppelt drin.
          Und da ich damit nicht gerechnet hab, hab ichs nicht geprüft.

          Gibt es nicht genau deshalb UNIQUE constraints? ;-)

          LG,
           CK

          1. Mahlzeit,

            Gibt es nicht genau deshalb UNIQUE constraints? ;-)

            Das Problem ist, die vorhandene Datenbank will ich nicht ändern, da sonst jedes Update viel Aufwand ist. Deshalb auch die Trigger ;)

            Und die Struktur hat keine ID. In jeder Spalte darf ein Wert mehrfach vorkommen, es dürfen nur keine exakt gleichen Einträge sein.

              
            DROP TABLE IF EXISTS `STOCKCURRENT`;  
            CREATE TABLE IF NOT EXISTS `STOCKCURRENT` (  
              `LOCATION` varchar(255) NOT NULL,  
              `PRODUCT` varchar(255) NOT NULL,  
              `ATTRIBUTESETINSTANCE_ID` varchar(255) DEFAULT NULL,  
              `UNITS` double NOT NULL,  
              UNIQUE KEY `STOCKCURRENT_INX` (`LOCATION`,`PRODUCT`,`ATTRIBUTESETINSTANCE_ID`),  
              KEY `STOCKCURRENT_FK_1` (`PRODUCT`),  
              KEY `STOCKCURRENT_ATTSETINST` (`ATTRIBUTESETINSTANCE_ID`),  
              CONSTRAINT `STOCKCURRENT_ATTSETINST` FOREIGN KEY (`ATTRIBUTESETINSTANCE_ID`) REFERENCES `ATTRIBUTESETINSTANCE` (`ID`),  
              CONSTRAINT `STOCKCURRENT_FK_1` FOREIGN KEY (`PRODUCT`) REFERENCES `PRODUCTS` (`ID`),  
              CONSTRAINT `STOCKCURRENT_FK_2` FOREIGN KEY (`LOCATION`) REFERENCES `LOCATIONS` (`ID`)  
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
            
            

            PRODUCT kann also für jedes angelegte Lager (LOCATION) vorkommen, aber es darf für Lager 1 nicht zweimal den gleichen Artikel geben. Die doppelten Einträge sind vermutlich das Resultat eines Bugs in meiner Software ;)

            Mein eigenes Frontend wird mit Sicherheit eine entsprechende Abfrage bekommen und die doppelten Einträge werden bereinigt. Mal sehen ob in der Wirkdatenbank der Fehler auch da ist oder nur in der Testversion.

            --
            42
            1. Moin M.,

              Gibt es nicht genau deshalb UNIQUE constraints? ;-)

              Das Problem ist, die vorhandene Datenbank will ich nicht ändern, da sonst jedes Update viel Aufwand ist. Deshalb auch die Trigger ;)

              Inwiefern viel Aufwand? Schreib doch Migrations?

              In Rails ist das zum Beispiel ziemlich gut gelöst. Dort ist die Datenbank quasi versioniert, jedesmal, wenn sich die Struktur ändert, wird ein Migrations-Script angelegt (ziemlich einfach, so eine Migration zu schreiben), dass die Struktur von der bestehenden Version verändert hin zur gewünschten Version. Sowas hab ich für ein PHP-Framework auch schonmal selber geschrieben, das lohnt sich halt wirklich weil es einiges an Arbeit erspart.

              Und die Struktur hat keine ID. In jeder Spalte darf ein Wert mehrfach vorkommen, es dürfen nur keine exakt gleichen Einträge sein.

              Man kann UNIQUE-Constraints auch auf mehrere Spalten auf einmal legen, in dem Fall muss dann die Kombination der Felder eindeutig sein.

              Ich sehe das immer wieder, dass Leute die Datenbank nur als „einfaches“ Storage benutzen. Dabei können die DBMS idR soviel mehr. Gerade im Bereich Konsistenz der Daten sind RDBMS richtig gut, darauf sind sie spezialisert. Warum also nicht nutzen?

              LG,
               CK

              1. Hello,

                Ich sehe das immer wieder, dass Leute die Datenbank nur als „einfaches“ Storage benutzen. Dabei können die DBMS idR soviel mehr. Gerade im Bereich Konsistenz der Daten sind RDBMS richtig gut, darauf sind sie spezialisert. Warum also nicht nutzen?

                Das bringt mich bei den neueren MySQL-Datenbanken immer wieder auf die Idee, das eigentliche Datenmodell vom Zugriffsmodell (Geschäftsregeln) mittels Triggers und Procedures von der API zu trennen. Da ist es dann nämlich auch ganz einfach möglich, eine Historie der Zugriffe (auch der Selects) zu erzeugen.

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                 ☻_
                /▌
                / \ Nur selber lernen macht schlau
                http://restaurant-zur-kleinen-kapelle.de
                1. Moin Tom,

                  Da ist es dann nämlich auch ganz einfach möglich, eine Historie der Zugriffe (auch der Selects) zu erzeugen.

                  Vorsicht! Eine Historie, erst recht, wenn sogar SELECTs protokolliert werden, kann die Datenbank sehr schnell sehr stark anwachsen lassen. Und die generierten Daten interessieren idR eh keinen.

                  Außerdem: Datensammelwut tut selten gut! :-)

                  LG,
                   CK

                  1. Hello,

                    Da ist es dann nämlich auch ganz einfach möglich, eine Historie der Zugriffe (auch der Selects) zu erzeugen.

                    Vorsicht! Eine Historie, erst recht, wenn sogar SELECTs protokolliert werden, kann die Datenbank sehr schnell sehr stark anwachsen lassen. Und die generierten Daten interessieren idR eh keinen.

                    Außerdem: Datensammelwut tut selten gut! :-)

                    Da fehlen dann in den DBMS mMn sowieso zwei wichtige Funktionen "Push_Changes_to_NSA()" und "Get_back_relevant_date_from_World_Storage()" ;-PP

                    Liebe Grüße aus dem schönen Oberharz

                    Tom vom Berg

                    --
                     ☻_
                    /▌
                    / \ Nur selber lernen macht schlau
                    http://restaurant-zur-kleinen-kapelle.de
              2. Mahlzeit,

                Inwiefern viel Aufwand? Schreib doch Migrations?

                Insofern, dass das Kassensystem eine Fremdsoftware ist und ich keine Ahnung hab wie sich in Zukunft die Datenbankstruktur ändert.
                Einen Trigger einzufügen ist kein Problem, wenn ich aber jedesmal die Struktur direkt beieinflussen muss, ist das deutlich mehr Aufwand.

                Das eigentliche Kassensystem ist in Java geschrieben und entzieht sich meiner direkten Kontrolle. Die WaWi, die ich auf der gleichen Datenbank aufbaue greift zwar auf Produktdaten zu, Updates erfolgend aber nur auf Basis der Trigger, ebenso wie die Anbindung des Onlineshops, was wieder Fremdsoftware ist.

                --
                42
                1. Moin M.,

                  Insofern, dass das Kassensystem eine Fremdsoftware ist und ich keine Ahnung hab wie sich in Zukunft die Datenbankstruktur ändert.

                  Ohje, das ist natürlich sehr ärgerlich. Ich musste auch mal so arbeiten: konsequenter Verzicht auf Constraints jeglicher Art, inkl. Primary Keys und Foreign Keys. Bin echt froh, davon inzwischen weg zu sein… insofern hast du mein vollstes Beileid.

                  LG,
                   CK

              3. hi,

                Ich sehe das immer wieder, dass Leute die Datenbank nur als „einfaches“ Storage benutzen. Dabei können die DBMS idR soviel mehr. Gerade im Bereich Konsistenz der Daten sind RDBMS richtig gut, darauf sind sie spezialisert. Warum also nicht nutzen?

                Geht mir genauso. Da werden Felder angelegt vom Type decimal, mit 10 Stellen Genauigkeit hinterm Komma und dann wird mit den Preisen, die als String ankommen, fleißig im Programmcode gerechnet, und nur dort und dann wird auch noch gerundet mitnm € hintendran ;)

                SCNR

    3. Hello,

      Moin M.,

      doofe Frage, aber bist du sicher, dass du nicht aus Versehen zweimal diesen Trigger eingerichtet hast?

      geht das überhaupt?
      Zumindest doch nicht unter demselben Namen, oder?

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
       ☻_
      /▌
      / \ Nur selber lernen macht schlau
      http://restaurant-zur-kleinen-kapelle.de
      1. Moin Tom,

        doofe Frage, aber bist du sicher, dass du nicht aus Versehen zweimal diesen Trigger eingerichtet hast?

        geht das überhaupt?
        Zumindest doch nicht unter demselben Namen, oder?

        Nicht mit gleichem Namen, nein.

        LG,
         CK

        1. Hello Christian,

          doofe Frage, aber bist du sicher, dass du nicht aus Versehen zweimal diesen Trigger eingerichtet hast?

          geht das überhaupt?
          Zumindest doch nicht unter demselben Namen, oder?

          Nicht mit gleichem Namen, nein.

          lass uns das Spielchen jetzt bitte nochmal auf den Punkt bringen, damit wir nachher nicht mehr im Grammatik- und Semantikgetrüpp  versinken können...

          "Derselbe Name" würde für mich bedeuten, in derselben Datenbank und womöglich sogar nur für dieselbe Tabelle.

          Der "gleiche Name" würde für mich bedeuten, "nur nicht für dieselbe Tabelle" oder ggf. sogar "nur nicht für dieselbe Spalte", je nach Datenbank. Ich kenn ja leider nur ein parr bisher und kann mir durchaus "Schmankerln" vorstellen.

          usw.

          Verwirrung ist on me now :-O

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://restaurant-zur-kleinen-kapelle.de
          1. Moin Tom,

            "Derselbe Name" würde für mich bedeuten, in derselben Datenbank und womöglich sogar nur für dieselbe Tabelle.

            Der "gleiche Name" würde für mich bedeuten, "nur nicht für dieselbe Tabelle" oder ggf. sogar "nur nicht für dieselbe Spalte", je nach Datenbank. Ich kenn ja leider nur ein parr bisher und kann mir durchaus "Schmankerln" vorstellen.

            ob ein Trigger-Name Tabellen-weit eindeutig sein muss oder Datenbank-weit, kann dir am besten die Dokumentation verraten. Ich bin eher PostgreSQL-Nutzer, mit einigen Einfärbungen aus dem Bereich Oracle und MS SQL. Und wäre ich ein provokativer Mensch, würde ich, frei nach Ciceros „Ceterum censeo Carthaginem esse delendam“, jedes Posting mit „im Übrigen bin ich der Meinung, dass MySQL verbrannt werden sollte“ schließen ;>

            LG,
             CK

            1. Hello CK,

              [...] Und wäre ich ein provokativer Mensch, würde ich, frei nach Ciceros „Ceterum censeo Carthaginem esse delendam“, jedes Posting mit „im Übrigen bin ich der Meinung, dass MySQL verbrannt werden sollte“ schließen ;>

              Das ist jetzt aber sachon wieder mehrdeutig ;-O

              Würdest Du dein Posting mit obigem Satz abschließen, oder würderst Du die Darastellung ders Postings, ob eines solchen Satzes, lieber gleich wieder schließen, um nicht "aus Versehen" eine Antwort zu schreiben?

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
               ☻_
              /▌
              / \ Nur selber lernen macht schlau
              http://restaurant-zur-kleinen-kapelle.de
              1. Moin Tom,

                Würdest Du dein Posting mit obigem Satz abschließen, oder würderst Du die Darastellung ders Postings, ob eines solchen Satzes, lieber gleich wieder schließen, um nicht "aus Versehen" eine Antwort zu schreiben?

                Da ich kein provokativer Mensch bin tue ich gar nichts dergleichen ;-) Aber wenn ich es wäre, würde ich immer noch versuchen ein hilfsbereiter Mensch zu sein und würde also antworten, aber trotzdem so abschließen ;-)

                LG,
                 CK

            2. Mahlzeit,

              „im Übrigen bin ich der Meinung, dass MySQL verbrannt werden sollte“ schließen ;>

              Das klappt aber nur, wenn die Massenhoster auf was anderes umsteigen.
              Auf meinem Server kann ich natürlich einsetzen, was ich will, aber viel, was meine Kunden auf meinen Servern einsetzen braucht Mysql und viel Software, die ich schreibe muss auf Servern laufen, die nur Mysql anbieten.

              Somit würde sich deine Meinung nur durchsetzen lassen, wenn sich das ändert ;)
              Mir persönlich ist es egal, was ich nutze, solange es funktioniert.

              --
              42
            3. Moin,

              Und wäre ich ein provokativer Mensch, würde ich, frei nach Ciceros „Ceterum censeo Carthaginem esse delendam“, jedes Posting mit „im Übrigen bin ich der Meinung, dass MySQL verbrannt werden sollte“ schließen ;>

              Warum?

              Grüße Marco

              --
              Ich spreche Spaghetticode - fließend.
              1. Moin misterunknown,

                Und wäre ich ein provokativer Mensch, würde ich, frei nach Ciceros „Ceterum censeo Carthaginem esse delendam“, jedes Posting mit „im Übrigen bin ich der Meinung, dass MySQL verbrannt werden sollte“ schließen ;>

                Warum?

                Na, um zu provozieren. Hab ich doch geschrieben ;-)

                Alles gut. Nur ein Scherz.

                LG,
                 CK