Robert: Gibt es sowas wie UPDATE or INSERT ?

Hallöle,

Ich hab eine Tabelle aus
userid, itemid, timeoflastuse

Wenn der User jetzt das Item benutzt, soll die timeoflastuse gesetzt werden.

Jetzt gibt es zwei Fälle:
Der User hat das Item schon mal benutzt, dann existiert ja der Datensatz schon und es muß nur timeoflastuse auf den aktuellen Stand gebracht werden - also ein
UPDATE mytable SET timeoflastuse=NOW() WHERE userid=17 AND itemid=42.

Und dann gibt es noch den Fall, daß der User das Item das erste Mal benutzt. Dann muß der Datensatz eingefügt werden:
INSERT INTO mytable SET userid=17, itemid=42, timeoflastuse=NOW()

Um rauszufinden, welcher Fall vorliegt, muß ich aber vorher abfragen, ob das der Fall ist, also
SELECT COUNT(*) FROM mytable WHERE userid=17 AND itemid=42

Das gefällt mir irgendwie nicht - insbesondere weil dann auch noch die Gefahr besteht, daß zwei parallel laufende Prozesse ggf. dazu führen, daß doppelte Einträge entstehen (Prozeß A frag ab, bekommt 0 - dann fragt Prozeß B ab, bekommt ebenfalls 0, dann führt jeder der Prozesse seinen INSERT durch). Ok, das könnte man noch mit einem UNIQUE INDEX auf userid + itemid vermeiden.

Aber noch lieber wäre mir, wenn das ganze mit einem einzigen SQL-Statement ginge ...
cu,
Robert

  1. echo $begrueszung;

    Aber noch lieber wäre mir, wenn das ganze mit einem einzigen SQL-Statement ginge ...

    Schau mal, ob dir REPLACE was nutzt.

    Ansonsten gäbe es da noch table locks

    echo "$verabschiedung $name";

    1. Hallöle,

      Schau mal, ob dir REPLACE was nutzt.

      Ja, dankeschön, das ist genau das gewünschte!

      Muchas Gracias.

      cu,
      Robert

      1. Hallo!

        Schau mal, ob dir REPLACE was nutzt.

        Ja, dankeschön, das ist genau das gewünschte!

        Allerdings löscht REPPLACE die alte Zeile komplett und trägt nur die neuen Daten ein.

        Ich gehe mal davon aus dass Du MySQL verwendest. Seit 4.1 gibt es bei INSERT "ON DUPLICATE KEY UPDATE":

        If you specify the ON DUPLICATE KEY UPDATE clause (new in MySQL 4.1.0), and a row is inserted that would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an UPDATE of the old row is performed. For example, if column a is declared as UNIQUE  and contains the value 1, the following two statements have identical effect:

        mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
            -> ON DUPLICATE KEY UPDATE c=c+1;

        mysql> UPDATE table SET c=c+1 WHERE a=1;

        siehe http://dev.mysql.com/doc/mysql/en/insert.html

        Grüße
        Andreas

        --
        SELFHTML Tipps & Tricks: http://aktuell.de.selfhtml.org/tippstricks/
        1. Hallöle,

          Allerdings löscht REPPLACE die alte Zeile komplett und trägt nur die neuen Daten ein.

          Reicht mir im Prinzip (es gibt in der Tabelle nur genau die 3 Spalten).

          Ich gehe mal davon aus dass Du MySQL verwendest. Seit 4.1 gibt es bei INSERT "ON DUPLICATE KEY UPDATE":

          Das klingt allerdings noch interessanter.
          Werd ich verwenden - gefällt mir irgendwie besser als Löschen und Einfügen.

          cu,
          Robert

        2. Hallöle,

          If you specify the ON DUPLICATE KEY UPDATE clause (new in MySQL 4.1.0),

          jargl. Auf meinem System läuft 4.1.10, auf dem Zielsystem 4.0.18
          ==> doch die Replace-Variante.

          cu,
          Robert

  2. yo,

    es ist immer ganz interessant zu wissen, welches dbms du benutzt und welche version. ich gehe mal von mysql in verbindung mit php aus. mir ist es nicht bekant, dass es unter mysql so einen befehl gibt, der erst versucht den datensatz zu updaten und falls nicht vorhanden einen insert draus zu machen.

    du kannst aber einen anderen weg gehen, als vorher ein select abzuschicken. du kannst einfach ein update auf verdacht machen und wenn der kein erfolg hat, dann ein insert hinterherschicken. und falls der eine eindeutigkeit wegen eines parallelprozess verletzt, bestehend aus user_id und item_id, dann kann man die fehlermeldung abfangen und wieder ein update machen.

    Ilja

    1. Hallöle,

      es ist immer ganz interessant zu wissen, welches dbms du benutzt und welche version.

      Ups, vergessen.

      ich gehe mal von mysql in verbindung mit php aus.

      Bingo ;-)

      mir ist es nicht bekant, dass es unter mysql so einen befehl gibt, der erst versucht den datensatz zu updaten und falls nicht vorhanden einen insert draus zu machen.

      REPLACE - existiert und funktioniert!
      Siehe Posting von dedlfix

      cu,
      Robert

      1. yo,

        REPLACE - existiert und funktioniert!

        REPLACE macht nicht das, was du wilst, bzw. was du wolltest. REPLACE löscht den alten datensatz und wird einen neuen anlegen. was du aber gesucht hast, war ein UPDATE, falls einer vorhanden ist und wenn nicht ein INSERT absetzen. und genau das gibt es nicht unter mysql.

        REPLACE mag für deine zwecke reichen, aber gerade bei dbms mit fremdschlüsseln und referenzieller integrität würden schwierigkeiten auftauchen. auch bei mysql kann dies zu schwierigkeiten führen, falls du zum beispiel in der betroffenen tabelle einen autoincrement PK hast, den anderen tabellen als fremdschlüssel führen. dann ist nämlich trauer mit REPLACE angesagt.

        Ilja

        1. Hello,

          REPLACE - existiert und funktioniert!

          REPLACE macht nicht das, was du wilst, bzw. was du wolltest. REPLACE löscht den alten datensatz und wird einen neuen anlegen. was du aber gesucht hast, war ein UPDATE, falls einer vorhanden ist und wenn nicht ein INSERT absetzen. und genau das gibt es nicht unter mysql.

          Wie jetzt?

          REPLACE ändert die Daten des vorhandenen Datensatzes, ud  wenn keiner vorhanden ist, legt es einen neuen an, auch unter MySQL. Ein Problem besteht aber, wenn Unique Keys vorhanden sind, dann verschwindet der alte Datensatz auch dann, wenn das Filterkriterium gar nicht DEN Datensatz gemeint hat.

          Harzliche Grüße aus http://www.annerschbarrich.de

          Tom

          --
          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
          Nur selber lernen macht schlau
          1. yo,

            REPLACE ändert die Daten des vorhandenen Datensatzes, ud  wenn keiner vorhanden ist, legt es einen neuen an, auch unter MySQL.

            das lese ich unter der mysql docu aber ganz anders.

            http://dev.mysql.com/doc/mysql/en/replace.html

            Ein Problem besteht aber, wenn Unique Keys vorhanden sind, dann verschwindet der alte Datensatz auch dann, wenn das Filterkriterium gar nicht DEN Datensatz gemeint hat.

            und in der doku steht auch, dass ein replace ohne einen pk oder unique nicht wirklich sinn macht....

            Ilja

            1. Hello,

              das lese ich unter der mysql docu aber ganz anders.

              http://dev.mysql.com/doc/mysql/en/replace.html

              Und hast DSu das Verhalten auch ausprobiert?
              Auch das Papioer von MySQL ist geduldig und alles wird wirklich nicht glasklar und richtig beschrieben.

              Ein Problem besteht aber, wenn Unique Keys vorhanden sind, dann verschwindet der alte Datensatz auch dann, wenn das Filterkriterium gar nicht DEN Datensatz gemeint hat.

              und in der doku steht auch, dass ein replace ohne einen pk oder unique nicht wirklich sinn macht....

              Ohne PK ist es wahrlich nicht sehr sinnvoll und eine weiteren Unique Key sollte die Tabelle dann auch nicht haben. Sonst treten nämlich die von Dir (und mir kurz) beschriebenen Seiteneffekte auf. Irgendwelche Sätze verschwinden einfach, weil der Unique-Key schon belegt war, aber der neue höhere Priorität hat.

              Harzliche Grüße aus http://www.annerschbarrich.de

              Tom

              --
              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
              Nur selber lernen macht schlau
              1. yo,

                Und hast DSu das Verhalten auch ausprobiert?
                Auch das Papioer von MySQL ist geduldig und alles wird wirklich nicht glasklar und richtig beschrieben.

                also ich sage mal, auf die doku von mysql kann man sich recht gut verlassen. und ich denke, es liegt an dir, es zu beweisen, wenn etwas an der doku nicht stimmen sollte und weniger an mir.

                wie auch immer, laut doku wird REPLACE immer nur ein INSERT hervorrufen und niemals ein UPDATE.

                Ilja

                1. Hello,

                  Und hast DSu das Verhalten auch ausprobiert?
                  Auch das Papioer von MySQL ist geduldig und alles wird wirklich nicht glasklar und richtig beschrieben.

                  also ich sage mal, auf die doku von mysql kann man sich recht gut verlassen. und ich denke, es liegt an dir, es zu beweisen, wenn etwas an der doku nicht stimmen sollte und weniger an mir.

                  wie auch immer, laut doku wird REPLACE immer nur ein INSERT hervorrufen und niemals ein UPDATE.

                  Ja, da habe ich mich auch falsch ausgedrückt. Du hast es besser gesagt. Ein Update findet nicht statt, denn das würde nur die bezogenen Spalten und die per Typ betroffenen ändern, und die anderen in Ruhe lassen.

                  REPLACE löscht die betroffenen Datensätze und fügt den neuen ein.
                  Wenn jetzt aber mehrere Datensätze durch einen Unique-Key betroffen sind, können durch ein REPLACE auch mehrere alte gelöscht werden.

                  Harzliche Grüße aus http://www.annerschbarrich.de

                  Tom

                  --
                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                  Nur selber lernen macht schlau
  3. Hello,

    da zitiere ich einfach mal einen Tipp, den Sven Rautenberg mir mal gegeben hat;
    viellicht kannst Du den auch verwerten:

    CREATE TABLE test1 (
      zahl int(11) NOT NULL default '0',
      ts1 timestamp(14) NOT NULL,
      ts2 timestamp(14) NOT NULL default '00000000000000'
    ) TYPE=MyISAM;

    INSERT INTO test1 (zahl, ts2) VALUES (2, NULL);

    SELECT * FROM test1;
    zahl  ts1               ts2
    2     20050308100309    20050308100309

    UPDATE test1 SET zahl = 3 WHERE zahl = 2;

    SELECT * FROM test1;
    zahl  ts1               ts2
    3     20050308100542    20050308100309

    Die erste Timestamp-Spalte wird bei jedem schreibenden Zugriff geändert, die zweite nur beim Insert, oder wenn man sie eben dediziert anspricht.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau