Niko: Welche Einträge wurden bei einer UPDATE anfrage geändert??

Hallo zusammen,

Ich stehe gerade vor folgendem Problem und finde auch über google.de keine Lösung:

Ich möchte gerne nach einer UPDATE - Anfrage an eine MySQL Datenbank herausfinden, welche Zeilen genau geändert wurden! Also so ähnlich wie mysql_affected_rows(), nur dass ich eben nicht die Anzahl, sondern die ids oä. haben möchte. Diese möchte ich dann nämlich in eine Logdatei schreiben in der Form:
Anfrage: UPDATE - Geändert: (und hier dann die geänderten ids)

Ist das irgendwie möglich? Danke schonmal für die Hilfe!

Lg Niko

  1. Hallo Niko,

    Ich stehe gerade vor folgendem Problem und finde auch über google.de keine Lösung:

    Ich möchte gerne nach einer UPDATE - Anfrage an eine MySQL Datenbank herausfinden, welche Zeilen genau geändert wurden!

    Also so ähnlich wie mysql_affected_rows(), nur dass ich eben nicht die Anzahl, sondern die ids oä. haben möchte. Diese möchte ich dann nämlich in eine Logdatei schreiben in der Form:
    Anfrage: UPDATE - Geändert: (und hier dann die geänderten ids)

    Du könntest mit einem UPDATE-Trigger die Datensätze, die geändert werden, in eine Tabelle schreiben und diese anschließend auswerten. Dies setzt MySQL 5.0.2 oder neuer voraus.

    Freundliche Grüße

    Vinzenz

    1. Hallo Vinzenz,

      Danke erstmal für die Antwort. :)

      Du könntest mit einem UPDATE-Trigger die Datensätze, die geändert werden, in eine Tabelle schreiben und diese anschließend auswerten. Dies setzt MySQL 5.0.2 oder neuer voraus.

      Das geht dann bei mir leider nicht, weil meine Scripts auf einem gemieteten Server laufen und der hat MySQL v4.1.22! Da kann ich leider auch nichts dran ändern.

      Ich dachte mir jetzt, dass man vielleicht die WHERE Bedingungen aus der Anfrage irgendwie rausschneidet und sie an eine SELECT Anweisung anhängt. Dann müsste man doch theoretisch genau die Felder als Rückgabe erhalten, die von der UPDATE/DELETE Anweisung betroffen sind.
      Werde das gleich mal ausprobieren.

      Lg Niko

      1. Hallo Niko,

        Ich dachte mir jetzt, dass man vielleicht die WHERE Bedingungen aus der Anfrage irgendwie rausschneidet und sie an eine SELECT Anweisung anhängt. Dann müsste man doch theoretisch genau die Felder als Rückgabe erhalten, die von der UPDATE/DELETE Anweisung betroffen sind.

        jein.

        Ja, Du erhältst alle Datensätze, die potentiell geändert werden.
        Nein, Datensätze, die sich nicht ändern, werden nicht geändert (und sollten nicht erfasst werden, was bei der WHERE-Methode der Fall ist).

        Du könntest statt dessen mit einer TIMESTAMP-Spalte arbeiten und deren magisches Verhalten (bei Dir ON UPDATE CURRENT TIMESTAMP) arbeiten. Nach dem Update suchst Du Dir die Datensätze, deren Wert in dieser Spalte im fraglichen Zeitraum liegt.

        Bei konkurrierenden Zugriffen könntest Du ein Problem bekommen, die Datensätze sauber zu ermitteln. Wenn derartige Zugriffe kein Thema sind, dann sollte diese Methode es tun.

        Genau aus diesen Gründen hatte ich Dir die sauberere Trigger-Lösung vorgeschlagen. Vielleicht kannst Du Deinen Provider davon überzeugen, auf eine neuere MySQL-Version upzugraden :-)

        Freundliche Grüße

        Vinzenz

        1. echo $begrüßung;

          [...] ON UPDATE CURRENT TIMESTAMP [...]. Nach dem Update suchst Du Dir die Datensätze, deren Wert in dieser Spalte im fraglichen Zeitraum liegt.
          Bei konkurrierenden Zugriffen könntest Du ein Problem bekommen, die Datensätze sauber zu ermitteln.
          Genau aus diesen Gründen hatte ich Dir die sauberere Trigger-Lösung vorgeschlagen.

          Der Update-Trigger hat doch genau das gleiche Nebenläufigkeitsproblem wie der Timestamp-Vorschlag. Es sei denn, man erstellt den Trigger pro Session, und löscht ihn an dessen Ende wieder. Außerdem benötigt man noch eine TEMPORARY Table, in der der UPDATE-Trigger die Datensätzt festhält. Da fällt mir ein, dass man ohne Trigger ja auch mit der temporären Tabelle arbeiten kann. Die temporäre Tabelle existiert nur für die aktuelle Connection, wird also nicht von nebenläufigen Prozessen beeinflusst.

          - CREATE TEMPORARY TABLE temp ... mit einem Feld für die ID
           - INSERT INTO temp SELECT id FROM original WHERE ...
           - UPDATE original ... WHERE ...

          Und in temp hat man die IDs der geänderten Datensätze. Den Vorgang müsste man eigentlich noch in eine Transaktion kapseln (InnoDB vorausgesetzt), denn zwischen INSERT und UPDATE kann ja auch schon wieder was dazwischengekommen sein.

          echo "$verabschiedung $name";

        2. Hi,

          Ich dachte mir jetzt, dass man vielleicht die WHERE Bedingungen aus der Anfrage irgendwie rausschneidet und sie an eine SELECT Anweisung anhängt. Dann müsste man doch theoretisch genau die Felder als Rückgabe erhalten, die von der UPDATE/DELETE Anweisung betroffen sind.

          jein.

          Ja, Du erhältst alle Datensätze, die potentiell geändert werden.
          Nein, Datensätze, die sich nicht ändern, werden nicht geändert (und sollten nicht erfasst werden, was bei der WHERE-Methode der Fall ist).

          Und wenn man die WHERE-Klausel entsprechend erweitern wuerde?

          UPDATE tabelle SET spalte = 'xyz' WHERE id > 4711
          wuerde nur die Datensaetze mit id > 4711 wirklich veraendern, bei denen spalte derzeit *nicht* den Wert 'xyz' hat.

          Also wuerde ein
          SELECT ... FROM tabelle WHERE id > 4711 AND spalte != 'xyz'
          mir doch die liefern, die letztendlich wirklich zu aendern waeren ...

          Bei Aenderung mehrerer Spalten muesste man die Abfragen auf deren Aenderung allesamt per OR verknupefen - es reicht ja, wenn einer der aktuellen Spaltenwerte abweicht.
          Und sich Gedanken um die "Klammerung" machen -
          WHERE (originale WHERE-Klausel-Bedingungen) AND (spalte1 != '...' OR ... OR spalteX != '...')
          wuerd' ich vorschlagen, wenn ich mich da auf die Schnelle nicht vertue ...

          Und natuerlich will das ganze dann auch noch in eine Transaktion verpackt werden, wenn man konsistente Ergebnisse haben moechte ...

          MfG ChrisB

        3. Hi Vinzenz,

          jein.

          Ja, Du erhältst alle Datensätze, die potentiell geändert werden.
          Nein, Datensätze, die sich nicht ändern, werden nicht geändert (und sollten nicht erfasst werden, was bei der WHERE-Methode der Fall ist).

          Und wenn ich einmal vor und einmal nach der Operation ne SELECT-Anfrage mache und die beiden Ergebnisse vergleiche? Theoretisch sollte man damit ermitteln können, welche Datensätze sich geändert haben! Denke nur, dass das evtl. bei vielen geänderten Datensätzen ziemlich Rechenintensiv sein könnte, aber da kenn ich mich nicht so aus, ist jetzt nur ne Spekulation.

          Du könntest statt dessen mit einer TIMESTAMP-Spalte arbeiten und deren magisches Verhalten (bei Dir ON UPDATE CURRENT TIMESTAMP) arbeiten. Nach dem Update suchst Du Dir die Datensätze, deren Wert in dieser Spalte im fraglichen Zeitraum liegt.

          Bei konkurrierenden Zugriffen könntest Du ein Problem bekommen, die Datensätze sauber zu ermitteln. Wenn derartige Zugriffe kein Thema sind, dann sollte diese Methode es tun.

          Und was ist, wenn ich statt nem TIMESTAMP irgendeinen zufällig generierten Schlüssel einsetze? Wenn der lang genug ist dürfte es fast unmöglich sein, dass man zweimal den Gleichen bekommt. Gibt es da ne Möglichkeit wie ON UPDATE CURRENT TIMESTAMP?

          Genau aus diesen Gründen hatte ich Dir die sauberere Trigger-Lösung vorgeschlagen. Vielleicht kannst Du Deinen Provider davon überzeugen, auf eine neuere MySQL-Version upzugraden :-)

          Ja mal schauen. Hab da jetzt mal ne Anfrage gestellt und warte immernoch auf die Antwort: :)

          Zur WHERE Lösung: Das stellt sich jetzt als etwas schwieriger heraus, als ich gehofft hatte. Ich müsste ja einen String aus der Anfrage ausschneiden, nur wenn in der Anfrage mehrmals WHERE vorkommt wirds übel! Hätte da vlt jemand ne Idee?

          Lg Niko

          1. Hallo Niko,

            Und was ist, wenn ich statt nem TIMESTAMP irgendeinen zufällig generierten Schlüssel einsetze? Wenn der lang genug ist dürfte es fast unmöglich sein, dass man zweimal den Gleichen bekommt. Gibt es da ne Möglichkeit wie ON UPDATE CURRENT TIMESTAMP?

            Nein, das verändert ja auch Datensätze, die sonst nicht verändert werden. Diese Änderung wäre aber künstlich und würde das Ergebnis verfälschen :-)

            Zur WHERE Lösung: Das stellt sich jetzt als etwas schwieriger heraus, als ich gehofft hatte. Ich müsste ja einen String aus der Anfrage ausschneiden,

            diese wird doch sicher eh' dynamisch zusammengebaut. Auf gleiche Art und Weise baust Du Dir Dein Kontrollstatement zusammen, der Vorschlag von Chris sollte funktionieren.

            nur wenn in der Anfrage mehrmals WHERE vorkommt wirds übel!

            Ein SQL-Statement hat genau eine WHERE-Klausel, es sei denn das Statement enthält Unterabfragen, da kann jede Unterabfrage wiederum genau eine WHERE-Klausel enthalten, es sei denn die Unterabfrage enthält wiederum Unterabfragen ...

            Freundliche Grüße

            Vinzenz

            1. Aloa,

              diese wird doch sicher eh' dynamisch zusammengebaut. Auf gleiche Art und Weise baust Du Dir Dein Kontrollstatement zusammen, der Vorschlag von Chris sollte funktionieren.

              Naja...die wird zwar zusammengebaut, aber dann vollständig an eine Funktion sql_request() geschickt, welche dann ne Funktion sql_log() aufruft und nen mysql_request macht. die Funktion sql_log() bekommt also auch nur den vollständigen Request und soll diesen jetzt möglichst Sinnvoll in eine Logdatei eintragen! Müsste das also jetzt komplett umbauen, dass ich z.b. jede Klausel (WHERE, ORDER, GROUP BY etc.) einzeln übergebe und es dann zusammenbauen lasse.
              Das Ding ist eben, dass ich diese Logfunktion möglichst Allgemein und Universell halten möchte.

              Ein SQL-Statement hat genau eine WHERE-Klausel, es sei denn das Statement enthält Unterabfragen, da kann jede Unterabfrage wiederum genau eine WHERE-Klausel enthalten, es sei denn die Unterabfrage enthält wiederum Unterabfragen ...

              Ist nicht ganz richtig! Wenn ich z.b. sowas habe:
              UPDATE ....... WHERE spalte1 = 'blub WHERE' ...
              dann können auch mehr WHEREs drin vorkommen! Ich mein ist jetzt sehr unwarscheinlich, aber möglich und das stört mich irgendwie ^^

              Lg Niko

              1. Hi,

                Ein SQL-Statement hat genau eine WHERE-Klausel, [...]

                Ist nicht ganz richtig!

                Doch.

                Wenn ich z.b. sowas habe:
                UPDATE ....... WHERE spalte1 = 'blub WHERE' ...
                dann können auch mehr WHEREs drin vorkommen!

                Da taucht die Buchstabenkombination WHERE mehrfach drin auf, ja - aber es handelt sich trotzdem nicht um mehrere WHERE-*Klauseln*.

                Ich mein ist jetzt sehr unwarscheinlich, aber möglich und das stört mich irgendwie ^^

                Dann wirst du dir wohl einen kleinen Parser basteln muessen, der (My)SQL-(UPDATE-)Kommandos in ihre einzelnen Bestandteile aufteilt.
                (Vielleicht kann man sich bei phpMyAdmin diesbezueglich was abschauen, oder bei irgendeinem anderen Script, welches bspw. Code Highlighting fuer (My)SQL bereitstellt.)

                MfG ChrisB

        4. Hello,

          man kann auch zusätzlich eine Vorgangsnummer einstanzen.
          Dann kann man auch bei konkurrieendem Zugriff noch feststellen, durch wen der DS zuletzt geändert worden ist. Der Vorgang kann dann in der Logtabelle registiert werden. Einfach das Update-Statement dort ablegen.

          Ein harzliches Glückauf

          Tom vom Berg

          http://bergpost.annerschbarrich.de
          .

          --
          Nur selber lernen macht schlau
          1. Hallo Tom,

            man kann auch zusätzlich eine Vorgangsnummer einstanzen.

            und ändert damit Datensätze, die nicht geändert wurden ...
            Nein, das halte ich nicht für eine gute Idee.

            Freundliche Grüße

            Vinzenz

            1. Hello,

              man kann auch zusätzlich eine Vorgangsnummer einstanzen.

              und ändert damit Datensätze, die nicht geändert wurden ...
              Nein, das halte ich nicht für eine gute Idee.

              Das habe ich wohl gelesen, was Dunda geschrieben hast. Aber ich halte es je nach Anwendungsfall gar nicht für schlimm, wenn auch der Änderungswille eines Users registriert wird. Ob da nun vorher schon 'Thomas' im Feld Vorname stand und nun nur durch 'Thomas' ausgetauscht wurde ist doch egal. Der User hat am Satz manipuliert ;-))

              Oder gibt es einen wichtigen wissenschaftlichen Hintergrund, dass man sowas nicht als Änderung bezeichnen darf?

              Ein harzliches Glückauf

              Tom vom Berg

              http://bergpost.annerschbarrich.de
              .

              --
              Nur selber lernen macht schlau
              1. Hallo,

                man kann auch zusätzlich eine Vorgangsnummer einstanzen.

                und ändert damit Datensätze, die nicht geändert wurden ...
                Nein, das halte ich nicht für eine gute Idee.

                Oder gibt es einen wichtigen wissenschaftlichen Hintergrund, dass man sowas nicht als Änderung bezeichnen darf?

                das hängt schlicht und einfach von der Anforderung ab. Logisch.
                Ich halte es jedoch für fehlerhaft, in einem Änderungslog Datensätze aufzuführen, die nicht geändert wurden. Es ist widersinnig.

                Ob im Einzelfall ein Änderungswille vorliegt, kann ich nicht beurteilen.
                Ich schrieb daher, dass ich das nicht für eine gute Idee halte.
                Und von künstlichen Änderungen, die völlig überflüssig sind, halte ich noch weniger ...

                Prinzipiell halte ich meine Trigger-Lösung, die einfach in eine Protokolltabelle loggt (ohne nachfolgendes Wegschreiben in eine Logdatei) für eine saubere Lösung. Ein cronjob könnte aus dieser Tabelle das Änderungsprotokoll erzeugen.

                Freundliche Grüße

                Vinzenz

                1. Prinzipiell halte ich meine Trigger-Lösung, die einfach in eine Protokolltabelle loggt (ohne nachfolgendes Wegschreiben in eine Logdatei) für eine saubere Lösung. Ein cronjob könnte aus dieser Tabelle das Änderungsprotokoll erzeugen.

                  Immernoch keine Antwort vom Server-Hoster :(

                  @Tom: Ich glaub ma dann würde die Logdatei viel zu groß werden! Habe jetzt schon bedenken, ob das überhaupt Sinnvoll ist.

                  Lg Niko

                2. Hello,

                  Prinzipiell halte ich meine Trigger-Lösung, die einfach in eine Protokolltabelle loggt (ohne nachfolgendes Wegschreiben in eine Logdatei) für eine saubere Lösung. Ein cronjob könnte aus dieser Tabelle das Änderungsprotokoll erzeugen.

                  Die halte ich auch für eine Gute Lösung, funktioniert ja aber erwähnterweise erst ab MySQL 5.x

                  Nun erinnere ich bei diesem Thema nochmal an eine Frage von mir, die schon lange unbenatwortet im Archiv verschwunden ist.

                  Kann man mit MySQL-Triggern auch gezielt Exceptions erzeugen?
                  Mir geht es darum, den Trigger festellen zu lassen, ob das Update überhaupt erlaubt ist.
                  Und wenn dies nicht der Fall ist, einen Fehlercode / Fehlermeldung zurückgeben zu lassen.

                  Das hat bisher leider nur mit einem schmutzigen Trick geklappt, indem man einfach eine NEW.-Spalte anspricht, die es nicht gibt.

                  Ein harzliches Glückauf

                  Tom vom Berg

                  http://bergpost.annerschbarrich.de
                  .

                  --
                  Nur selber lernen macht schlau
                  1. Nun erinnere ich bei diesem Thema nochmal an eine Frage von mir, die schon lange unbenatwortet im Archiv verschwunden ist.

                    Wooow...üble Thread-Piraterie hier ^^

                    ... hmmpf immernoch keine Antwort vom Host :(

                    MfG

                    1. Hiho,

                      So hab grad erfahren, dass mein Hoster in ein paar Wochen auf MySQL 5 aufrüsten will! Damit ist die Triggerlösung wohl angenommen ;)

                      Danke euch nochmal für eure Hilfe und Zeit!

                      Lg Niko