Bug: Satz ändern, wenn nicht vorhanden, anlegen

Hi,

ich habe den Fall, dass ich einen Datensätz in MySQL ändern muss. Falls er nicht vorhanden ist, soll er angelegt werden.

Das habe ich so gelöst:
--- update ---
    if ( !mysql_affected_rows( $conn_id ) )
--- insert ---

Das gibt aber einen Fehler, wenn der Satz zwar vorhanden ist, aber die Änderung nicht ausgeführt wird, weil der zu ändernde Wert bereits gesetzt  ist.

mysql_affected_rows meldet: Nichts geändert, und bei Neuanlage des schon vorhandenen Satzes ergibt sich: Doppeleter Key.

Gibt es anstelle mysql_affected_rows etwas anderes? Ich möchte gerne den Extra- Zugriff auf die DB sparen, ob der Satz vorhanden ist.

Gruß, Bug

  1. Hallo,

    ich habe den Fall, dass ich einen Datensätz in MySQL ändern muss. Falls er nicht vorhanden ist, soll er angelegt werden.

    Gibt es anstelle mysql_affected_rows etwas anderes? Ich möchte gerne den Extra- Zugriff auf die DB sparen, ob der Satz vorhanden ist.

    ja, gibt es. Du musst nur umgekehrt denken: Füge einen Datensatz ein, falls der Datensatz bereits vorhanden ist, ändere ihn.

    Freundliche Grüße

    Vinzenz

    1. Moin!

      Gibt es anstelle mysql_affected_rows etwas anderes? Ich möchte gerne den Extra- Zugriff auf die DB sparen, ob der Satz vorhanden ist.

      ja, gibt es. Du musst nur umgekehrt denken: Füge einen Datensatz ein, falls der Datensatz bereits vorhanden ist, ändere ihn.

      Erfordert allerdings, dass der gemeinte Datensatz durch einen UNIQUE-Index eindeutig identifizierbar ist, und man diesen Wert beim INSERT-Versuch kennt. Sinnlos wäre der Versuch, an dieser Stelle einen auto_increment-Wert hochzählen zu lassen... :)

      - Sven Rautenberg

      --
      "Love your nation - respect the others."
      1. Hallo,

        ich halte die Variante:

        [1] versuche Datensatz per UPDATE zu ändern
        [2] prüfe ob genau ein Datensatz geändert wurde (mittels affected_rows etc)
        [3] wenn > 1 dann problem
             wenn 1 - dann okay, änderung ist ja bereits erfolgt
             wenn 0 - dann neuen Datensatz mit INSERT anlegen

        für optimal(er).

        Ist resourcenfreundlicher als

        • select count(*) ... if = 0 dann insert, sonst update oder
        • insert & hoffen auf Unique/Primary Key violation

        Ciao, Frank

        1. Moin!

          [1] versuche Datensatz per UPDATE zu ändern
          [2] prüfe ob genau ein Datensatz geändert wurde (mittels affected_rows etc)
          [3] wenn > 1 dann problem
               wenn 1 - dann okay, änderung ist ja bereits erfolgt
               wenn 0 - dann neuen Datensatz mit INSERT anlegen

          UPDATE liefert bei affected_rows im Normalfall nur dann eine 1, wenn tatsächlich etwas verändert wurde. Ein UPDATE ohne Veränderung liefert keinen affected_row.

          für optimal(er).

          Du weißt, was von Steigerungsformen des Worts "optimal" zu halten ist?

          Ist resourcenfreundlicher als

          • select count(*) ... if = 0 dann insert, sonst update oder

          Das will man sicherlich nicht.

          • insert & hoffen auf Unique/Primary Key violation

          Wenn die Daten und das Anwendungsszenario danach beschaffen sind, ist diese Methode eindeutig vorzuziehen. Pro Datensatz genau ein Query, atomar, macht keine Probleme im Multiuserbetrieb.

          - Sven Rautenberg

          --
          "Love your nation - respect the others."
          1. Hallo,

            UPDATE liefert bei affected_rows im Normalfall nur dann eine 1, wenn tatsächlich etwas verändert wurde. Ein UPDATE ohne Veränderung liefert keinen affected_row.

            Das ist aber rein mysql-spezifisch. Genauso wenig kann man das auf alle anderen DBMSe verallgemeinern wie das Gegenteil.

            Du weißt, was von Steigerungsformen des Worts "optimal" zu halten ist?

            Du darfst das gern für dich behalten.

            • insert & hoffen auf Unique/Primary Key violation
              Wenn die Daten und das Anwendungsszenario danach beschaffen sind, ist diese Methode eindeutig vorzuziehen. Pro Datensatz genau ein Query, atomar, macht keine Probleme im Multiuserbetrieb.

            So wunderschön pauschalisieren kannst auch nur du. Belege?

            Tschüss,
            Frank

            1. Moin!

              UPDATE liefert bei affected_rows im Normalfall nur dann eine 1, wenn tatsächlich etwas verändert wurde. Ein UPDATE ohne Veränderung liefert keinen affected_row.

              Das ist aber rein mysql-spezifisch. Genauso wenig kann man das auf alle anderen DBMSe verallgemeinern wie das Gegenteil.

              Es verhindert aber, dass der Ansatz "UPDATE, und wenn Null Datensätze verändert wurden, dann INSERT" vernünftig funktioniert.

              • insert & hoffen auf Unique/Primary Key violation
                Wenn die Daten und das Anwendungsszenario danach beschaffen sind, ist diese Methode eindeutig vorzuziehen. Pro Datensatz genau ein Query, atomar, macht keine Probleme im Multiuserbetrieb.

              So wunderschön pauschalisieren kannst auch nur du. Belege?

              Wenn ich einen externen unique-key habe, der einen zu importierenden Datensatz eindeutig auch innerhalb der eigenen Datenbank beschreibt, eignet der sich bei regelmäßig wiederkehrenden Updates der eigenen Datenbank prima für "INSERT ... ON DUPLICATE KEY UPDATE ...".

              Oder für was wolltest du Belege?

              - Sven Rautenberg

              --
              "Love your nation - respect the others."
              1. Hi,

                was meinst du mit "vernünftig funktioniert"?

                Unter Oracle konnte ich nichts finden, was der Funktionsweise von mysql entspricht und von MSSQL kann ich dir definitiv sagen, auch wenn die selben Werte wieder reingeschrieben werden, affected_rows / @@rowcount ergibt die anzahl der betroffenen Records. Oracle würd ich gern auch praktische verifizieren, kann ich aber nur von zuhause.

                Von daher macht da wohl mySql wieder 'ne Extra Wurst, dito für  "INSERT ... ON DUPLICATE KEY UPDATE ...".

                Belege: für "eindeutig vorzuziehen" vs. "eignet sich prima"

                Also lass uns das mal so festhalten:

                Für MySQL ist es wohl (am) optimal(sten), auf dieses INSERT ... ON DUPLICATE KEY UPDATE ... zu setzen.

                Für andere DBMSe gibt es wahrscheinlich bis ganz sicher andere und bessere Vorgehensweisen.

                Ich hatte geschrieben: "ich halte ... für optimal(er)" .. zu deiner Erinnerung.
                Wenn ich meine Variante für ein DBMS implementieren würde, wo die Funktionalität nicht in gleicher Form gewährleistet ist, dann würde ich mich wohl damit beschäftigen müssen, für das jeweilige DBMS zu optimalisieren.

                Und tschüss
                Frank

                1. echo $begrüßung;

                  [Zählung der affected rows]
                  Von daher macht da wohl mySql wieder 'ne Extra Wurst, dito für  "INSERT ... ON DUPLICATE KEY UPDATE ...".

                  Dieses Verhalten ist konfigurierbar. Dass nur wirklich geänderte Datensätze gezählt werden ist eine Default-Einstellung. Siehe mysql_affected_rows() den Absatz unter dem Example. (Um das CLIENT_FOUND_ROWS-Flag mit PHP verwenden zu können, muss man mysqli und real_connect() verwenden.)

                  echo "$verabschiedung $name";

                2. Hallo,

                  Oracle würd ich gern auch praktische verifizieren, kann ich aber nur von zuhause.

                  Oracle macht immer ein Update und liefert SQL%ROWCOUNT = 1, falls genau eine Zeile der Bedingung entspricht

                  ...

                  Für MySQL ist es wohl (am) optimal(sten), auf dieses INSERT ... ON DUPLICATE KEY UPDATE ... zu setzen.

                  Für andere DBMSe gibt es wahrscheinlich bis ganz sicher andere und bessere Vorgehensweisen.

                  Für Oracle kann je nach Situation ein MERGE sinnvoll sein

                  Ansonsten ist es in PL/SQL nicht unüblich einen INSERT abzusetzen und im Kollisionsfall die Exception DUP_VAL_ON_INDEX abzufangen und ein UPDATE durchzuführen.

                  Grüße
                  Marcus

                  --
                  si vis pacem, para iustitiam
    2. ja, gibt es. Du musst nur umgekehrt denken: Füge einen Datensatz ein, falls der Datensatz bereits vorhanden ist, ändere ihn.

      So etwas habe ich gesucht, danke.

      Bug