Mike: mysql fehler 1062 Doppler id finden

Hallo,

ich benötige die ID/key (autoincrementwert) einer Tabelle, wenn doppelt vorhanden.

Beispiel:

Tabelle:

id|wert
1|a
2|b
3|c
4|d

bei jedem neuen Eintrag benötige ich die erzeugte id zur weiteren Nutzung in einer anderen Tabelle. Das erhalte ich durch: mysql_query("select LAST_INSERT_ID()"),0);

Die wert-spalte ist unique, was natürlich im Konfliktfall somit keine id liefert, da nicht eingetragen. Dieser Fehler lässt sich ja noch abfangen mit: if(mysql_errno() == 1062))...

Doch damit erhalte ich immer noch nicht die betreffende id. Nun kann ich zwar eine erneute Abfrage machen um diese zu erfahren, doch das Manual lässt hoffen, dass auch die Fehlermeldung diese liefern könnte, allerdings verstehe ich die Aussage nicht im Manual:

Error: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)
Message: Duplicate entry '%s' for key %d
The message returned with this error uses the format string for ER_DUP_ENTRY_WITH_KEY_NAME.

Somit meine Frage: Komme ich an die ID des Dopplers anhand einer Rückgabe von mysql oder wie löst ihr so was?

Gruss
Mike

  1. Mahlzeit,

    ich benötige die ID/key (autoincrementwert) einer Tabelle, wenn doppelt vorhanden.

    Wie soll in einer auto_increment-Spalte eine ID doppelt vorkommen?

    Somit meine Frage: Komme ich an die ID des Dopplers anhand einer Rückgabe von mysql oder wie löst ihr so was?

    Entweder die höchste IDauslesen oder den nächsten auto_increment-Wert und dann eins abziehen.
    Ich versteh immer noch nicht, wie eine Spalte mit auto_increment überhaupt nen Doppelten Eintrag anmeckern kann, den vergibt doch mysql selbst und die Software hat von der Spalte nur zu lesen aber nie zu schreiben.
    Wenn du diese Spalte beschreibst, hast du einen Konzeptfehler.

    --
    42
    1. Tach!

      ich benötige die ID/key (autoincrementwert) einer Tabelle, wenn doppelt vorhanden.
      Wie soll in einer auto_increment-Spalte eine ID doppelt vorkommen?

      Aus dem weiteren Verlauf des OP-Textes geht hervor, dass nicht die ID gemeint ist, sondern der "wert"-Wert doppelt vorkommen kann.

      Entweder die höchste IDauslesen oder den nächsten auto_increment-Wert und dann eins abziehen.

      So etwas wäre dann aber auch ein Konzeptfehler. Die höchste vergebene ID ist vielleicht in den meisten Fällen die gerade eben vergebene, aber nicht immer, vor allem dann nicht, wenn über mehrere Verbindungen gleichzeitig in der Tabelle Datensätze eingefügt werden. Nur LAST_INSERT_ID() garantiert, dass die ID des von der aktuelle Verbindung eingefügten Datensatzes geliefert wird.

      dedlfix.

      1. Mahlzeit,

        Aus dem weiteren Verlauf des OP-Textes geht hervor, dass nicht die ID gemeint ist, sondern der "wert"-Wert doppelt vorkommen kann.

        dann ist das auslesen dieser ID ja kein Problem. Der soppelte Wert ist bekannt, da er grade nen Fehler geworfen hat. Dann einfach den Eintrag auslesen mit dieser Wert und schon hat man die ID.

        Nur LAST_INSERT_ID() garantiert, dass die ID des von der aktuelle Verbindung eingefügten Datensatzes geliefert wird.

        und wenn das Query fehlgeschlagen hat, wie komm ich an den Wert? Genau das war ja die Frage, zumidnest versteh ich sie so.

        --
        42
        1. Hallo,

          und wenn das Query fehlgeschlagen hat, wie komm ich an den Wert? Genau das war ja die Frage, zumidnest versteh ich sie so.

          nein, die Frage ob ich vielleicht an den korrospondierenden Autoincrement-Wert(in meinem Fall "id") zu dem Doppler komme, ohne eine erneute select-Abfrage. Also entweder aus der Mysql-Fehlermeldung oder einen anderen insert-Befehl.

          Gruss
          Mike

          1. Tach!

            und wenn das Query fehlgeschlagen hat, wie komm ich an den Wert? Genau das war ja die Frage, zumidnest versteh ich sie so.

            Ja, und ich kenne da auch keinen anderen Weg als über den eindeutigen Wert noch eine Abfrage zu stellen.

            nein, die Frage ob ich vielleicht an den korrospondierenden Autoincrement-Wert(in meinem Fall "id") zu dem Doppler komme, ohne eine erneute select-Abfrage. Also entweder aus der Mysql-Fehlermeldung oder einen anderen insert-Befehl.

            Was jedoch noch ginge: die nächste Query in Abhängigkeit vom Fehler zu formulieren. Ohne Fehler baut man den mysql_insert_id()-Wert in die Query ein, mit Fehler nimmt man stattdessen eine Subquery SELECT id FROM tabelle WHERE wert=der_wert. Damit spart man zwar eine Query, aber ich würde das vermutlich nicht so in der Praxis anwenden wollen, wenn diese Einsparung nicht superwichtig ist.

            dedlfix.

  2. Tach!

    bei jedem neuen Eintrag benötige ich die erzeugte id zur weiteren Nutzung in einer anderen Tabelle. Das erhalte ich durch: mysql_query("select LAST_INSERT_ID()"),0);

    Oder einfacher mit mysql_insert_id(). Eigentlich ist es aber besser, die bereits abgekündigten mysql_*-Funktionen nicht mehr zu verwenden, sondern mysqli_* oder PDO. Beide haben Äquivalente zu mysql_insert_id().

    Die wert-spalte ist unique, was natürlich im Konfliktfall somit keine id liefert, da nicht eingetragen. Dieser Fehler lässt sich ja noch abfangen mit: if(mysql_errno() == 1062))...

    Doch damit erhalte ich immer noch nicht die betreffende id. Nun kann ich zwar eine erneute Abfrage machen um diese zu erfahren, doch das Manual lässt hoffen, dass auch die Fehlermeldung diese liefern könnte, allerdings verstehe ich die Aussage nicht im Manual:

    Error: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)
    Message: Duplicate entry '%s' for key %d
    The message returned with this error uses the format string for ER_DUP_ENTRY_WITH_KEY_NAME.

    Der doppelte Eintrag %s ist der Wert der Unique-Spalte, in deinem Fall also das was du als "wert" einfügen wolltest. Das kennst du ja aber schon und musst es nicht aus der Fehlermeldung klauben. %d lässt auf eine Zahl schließen. Damit kann eigentlich nicht der Primärschlüssel gemeint sein, denn der kann auch nichtnumerisch sein. Aber wenn man diesen Fehler mal provoziert, sieht man was wirklich vorliegt, nämlich der Name vom Unique-Index, also letztlich doch ein String. Jedenfalls ist das eine für deinen Fall unwichtige Information.

    Somit meine Frage: Komme ich an die ID des Dopplers anhand einer Rückgabe von mysql oder wie löst ihr so was?

    Da der "wert"-Wert eindeutig (und hoffentlich NOT NULL) ist, kannst du problemlos darüber die zugehörige ID ermitteln.

    dedlfix.

    1. Hallo,

      bei jedem neuen Eintrag benötige ich die erzeugte id zur weiteren Nutzung in einer anderen Tabelle. Das erhalte ich durch: mysql_query("select LAST_INSERT_ID()"),0);

      Oder einfacher mit mysql_insert_id(). Eigentlich ist es aber besser, die bereits abgekündigten mysql_*-Funktionen nicht mehr zu verwenden, sondern mysqli_* oder PDO. Beide haben Äquivalente zu mysql_insert_id().

      mit mysqli hast Du natürlich recht, habe mich aber leider noch nicht damit anfreunden können, "...was der Bauer nicht kennt... ;-)

      Was mysql_insert_id() betrifft, da bin ich nicht so sicher, denn das habe ich früher benutzt und Probleme bekommen, die bei LAST_INSERT_ID() nicht auftraten. Jetzt frag mich nicht, welches Problem das war, ich weiß es nicht mehr genau, nur dass ich das gewünschte Ergebnis nicht 100% verlässlich auch bekam bei irgendeinem Script. Wenn's mir wieder einfällt, reiche ich es nach.

      Somit meine Frage: Komme ich an die ID des Dopplers anhand einer Rückgabe von mysql oder wie löst ihr so was?

      Da der "wert"-Wert eindeutig (und hoffentlich NOT NULL) ist, kannst du problemlos darüber die zugehörige ID ermitteln.

      Damit meinst Du jetzt aber vermutlich wieder eine erneute Select-Abfrage? Und genau das wollte ich ja vermeiden.

      Gruss
      Mike

    2. Hi,

      Oder einfacher mit mysql_insert_id(). Eigentlich ist es aber besser, die bereits abgekündigten mysql_*-Funktionen nicht mehr zu verwenden, sondern mysqli_* oder PDO.

      2 Fragen hierzu:

      1. Wird abgeschafft? Was bedeutet das? Muß ich dann sämtliche Scripte umschreiben, innerhalb derer ich sie benutzt hatte?

      2. Was ist besser? mysqli oder PDO?

      Lukas

      1. Mahlzeit,

        1. Wird abgeschafft? Was bedeutet das? Muß ich dann sämtliche Scripte umschreiben, innerhalb derer ich sie benutzt hatte?

        Ja

        1. Was ist besser? mysqli oder PDO?

        Kommt auf die Vorraussetzungen an. Wenn z.B. PDO auf dem Server nicht installiert ist, dürfte Mysqli die bessere Wahl sein ;)

        --
        42
      2. Tach!

        Eigentlich ist es aber besser, die bereits abgekündigten mysql_*-Funktionen nicht mehr zu verwenden, sondern mysqli_* oder PDO.

        1. Wird abgeschafft? Was bedeutet das? Muß ich dann sämtliche Scripte umschreiben, innerhalb derer ich sie benutzt hatte?

        Das PHP-Handbuch zeigt zu jeder der mysql_*-Funktionen schon seit Monaten und auf der englischen Originalseite (die deutsche Übersetzung zeigt das noch nicht), dass diese Funktionen ab PHP 5.5.0 "deprecated" also missbilligt sind. Das ist ein erstes Anzeichen dafür, dass diese Funktionen mittel- oder langfristig verschwinden werden. Das passiert vermutlich noch nicht in der 5.5.x sondern erst später. Natürlich ist den PHP-Leuten bewusst, dass viele diese Funktionen verwenden und sie deshalb keine Hau-Ruck-Aktionen machen können. Es ist also noch viel Zeit, die man ungenutzt vertrödeln kann, bevor es wirklich ernst wird.

        Außerdem verschwinden diese Funktionen nicht zu einem Stichtag weltweit aus dem Angebot, sondern sie sind nur in neueren PHP-Versionen nicht mehr enthalten. Alte Versionen laufen weiterhin damit. Doch irgendwann will man einfach diese alten Versionen nicht mehr verwenden oder unterstützen, besonders wenn dazu keine Sicherheitspatche mehr ausgegeben werden. Die Linux-Distributionen, XAMP-Pakete, Hoster und so weiter werden also in (geschätzt) ein paar Jahren auch nur noch PHP ohne die mysql_*-Funktionen im Angebot haben. Natürlich werden sie es vorher ankündigen, und natürlich werden viele bis auf den letzten Drücker mit dem Umschreiben ihrer Scripte oder der Suche nach alternativen Anwendungen warten.

        Damit lautet die Antwort konkreter: Du wirst nicht umhinkommen, die Scripte umzuschreiben, die in ferner Zukunft noch laufen sollen, wenn dir dann kein Museums-PHP mehr zur Verfügung steht.

        1. Was ist besser? mysqli oder PDO?

        mysqli ist näher an den von der MySQL-API zur Verfügung gestellten Funktionalität dran. PDO ist eine Abstraktion, die auf vielen DBMS-Systemen generell lauffähig sein möchte. (Unterschiede in den SQL-Dialekten kann und will es jedoch nicht ausgleichen.) PDO bietet alles, was man meistens so braucht, und das teilweise in einfacherer/anwenderfreundlicherer Form als mysqli. Aber einige eher seltene Spezialfälle wird man mit PDO nicht erledigen können.

        dedlfix.

  3. hi,

    Somit meine Frage: Komme ich an die ID des Dopplers anhand einer Rückgabe von mysql oder wie löst ihr so was?

    Du könntest ein zusätzliches Feld in der Tabelle anlegen und darin den Wert erhöhen, immer dann, wenn versucht wird, einen bereits vorhandenen Wert da einzufügen.

    my $dbh = Methods->dbh('myweb');
    $dbh->do(q(
        insert into lastid(val)values('testxxx')
        on duplicate key update id=LAST_INSERT_ID(id), upt = upt+1
    ));
    print Dumper $dbh->selectrow_array('select last_insert_id(), upt from lastid where id = last_insert_id()');
    __END__
    $dbh->do(qq(
        create table lastid(
            id int(11) unsigned NOT NULL AUTO_INCREMENT,
            val varchar(123) not null default '',
            upt int(11) unsigned NOT NULL default 0,
            primary key(id),
            unique key val (val)
        )
    ));

    Horst

  4. ich benötige die ID/key (autoincrementwert) einer Tabelle, wenn doppelt vorhanden.

    id|wert
    1|a
    2|b
    3|c
    4|d

    Die wert-spalte ist unique, was natürlich im Konfliktfall somit keine id liefert, da nicht eingetragen. Dieser Fehler lässt sich ja noch abfangen mit: if(mysql_errno() == 1062))...

    Doch damit erhalte ich immer noch nicht die betreffende id.

    Somit meine Frage: Komme ich an die ID des Dopplers

    mysql> insert into tabelle (wert) values ("a") on duplicate key update id=last_insert_id(id);

    mysql> select last_insert_id(), row_count();
    +------------------+-------------+
    | last_insert_id() | row_count() |
    +------------------+-------------+
    |                1 |          -1 |
    +------------------+-------------+

    mysql> insert into tabelle (wert) values ("x") on duplicate key update id=last_insert_id(id);

    mysql> select last_insert_id(), row_count();
    +------------------+-------------+
    | last_insert_id() | row_count() |
    +------------------+-------------+
    |                5 |           1 |
    +------------------+-------------+

    1. Hallo,

      id|wert
      1|a
      2|b
      3|c
      4|d

      mysql> insert into tabelle (wert) values ("a") on duplicate key update id=last_insert_id(id);

      mysql> select last_insert_id(), row_count();
      +------------------+-------------+
      | last_insert_id() | row_count() |
      +------------------+-------------+
      |                1 |          -1 |
      +------------------+-------------+

      das scheint ähnlich wie Hottis Lösung ohne die Extraspalte. Leider verstehe ich den Hintergrund nicht, das Manual ist mir da auch ein wenig zu Fachchinesisch.

      Für mich sieht das so aus:
      mysql> insert into tabelle (wert) values ("a") on duplicate key update id=last_insert_id(id);

      Füge "a" ein in Tabelle, wenn Doppler dann verändere den Key(also ID), was aber ja kontraproduktiv wäre und somit nicht sein kann. Also was genau macht "on duplicate key update id=last_insert_id(id)"? Für Dummys ;-)

      Gruss
      Mike

      1. moin,

        Füge "a" ein in Tabelle, wenn Doppler dann verändere den Key(also ID), was aber ja kontraproduktiv wäre und somit nicht sein kann. Also was genau macht "on duplicate key update id=last_insert_id(id)"? Für Dummys ;-)

        on duplicate key greift immer dann, wenn in das Feld, was mit unique deklariert ist, derselbe Wert erneut eingefügt werden soll.

        Die mysql Funktion LAST_INSERT_ID(id) ===beachte den Feldnamen im Argument=== liefert bei der nächsten Abfrage exakt den bereits vorhandenen auto_increment-Wert. In meinem zusätzlichen Feld wird in diesem Fall (on duplicate key) der Wert erhöht. Somit kannst du feststellen, ob es sich um einen neuen Eintrag handelt (upt ist =0).

        Wenn der Wert im Feld upt > 0 ist, wurden Inserts ausgeführt mit doppelten Einträgen, das kann jedoch auch in der Vergangenheit liegen. Zur Laufzeit ist es damit also auch nicht feststellbar, ob das gerade in dem Moment passiert oder irgendwann einmal vorher. Wenn Du das ganz genau brauchst, setze einen Trigger der beim Update zuschlägt und eine History-Tabelle beschreibt.

        Horst

      2. mysql> insert into tabelle (wert) values ("a") on duplicate key update id=last_insert_id(id);

        Füge "a" ein in Tabelle, wenn Doppler dann verändere den Key(also ID), was aber ja kontraproduktiv wäre und somit nicht sein kann. Also was genau macht "on duplicate key update id=last_insert_id(id)"? Für Dummys ;-)

        Das, was nach on duplicate key kommt, wird ausgeführt, sobald eben genau der beschriebene Fall Eintritt, ein Schlüsselwert würde doppelt vorhanden sein. Soweit ist dir das ja schon klar.Beachte, dass das Update die Zeile betrifft, in der der doppelte Wert vorhanden ist.

        last_insert_id() liefert, auch das ist dir natürlich bekannt, die ID der letzten eingefügten Zeile.

        last_insert_id(argument) hingegen _setzt_ den Wert, der beim nächsten Aufruf von last_insert_id() zurückgegeben wird, und gibt selbst ebenfalls schon den übergebenen Wert zurück.

        Beispiel:

        mysql> insert into tabelle irgendwelches_blabla;

        mysql> select last_insert_id();  # liefert ID der eben eingefügten Zeile
        +------------------+
        | last_insert_id() |
        +------------------+
        |               42 |
        +------------------+

        mysql> select last_insert_id(23); # setzt den last-insert-id-Wert für diesen und alle folgenden Aufrufe auf 23
        +--------------------+
        | last_insert_id(23) |
        +--------------------+
        |                 23 |
        +--------------------+

        mysql> select last_insert_id(); # liefert, wie eben festgelegt, 23
        +------------------+
        | last_insert_id() |
        +------------------+
        |               23 |
        +------------------+

        Beachte den dritten Aufruf von last_insert_id(): Es wurde zwischen erstem und drittem Aufruf keine Zeile eingefügt, trotzdem liefert last_insert_id() nicht mehr 42 wie eingangs, sondern 23 – wie im zweiten Aufruf festgelegt.

        Zu deiner Problemlösung:

        mysql> insert into tabelle (wert) values ("a") on duplicate key update id=last_insert_id(id);

        Angenommen, "a" ist bereits vorhanden, deshalb wird jetzt on duplicate key update … ausgeführt.

        1. Offensichtlich wird hier erstmal last_insert_id mit der id der betreffenden, schon vorhandenen Zeile aufgerufen ("last_insert_id(id)").

        2. a) last_insert_id merkt sich die Spalte id der vorhandenen Zeile.
           b) last_insert_id gibt die Spalte id der vorhandenen Zeile zurück.

        3. Die Spalte id der vorhandenen Zeile wird mit ihrem eigenen Wert überschrieben, denn last_insert_id() gibt ja, siehe 2b), genau diesen zurück (de facto passiert gar nichts, denn MySQL ändert nichts, was nicht geändert werden muss).

        Zu guter Letzt bekommst du wegen 2a) mit allen nachfolgenden Aufrufen von last_insert_id immer wieder die ID der betreffenden Zeile geliefert (lies: so lange, bis eine neue Zeile eingefügt und damit eine neue ID erzeugt wird oder du last_insert_id wieder mit Argument aufrufst).

        Da, wie in 3. schon beschrieben, jedoch keine Änderung vorgenommen wird, ist der Rückgabewert von row_count() 0. Anhand dieses Wertes lässt sich unterscheiden, ob eine neue Zeile eingefügt wurde (row_count() == 1, neue ID in last_insert_id()) oder bereits eine vorhanden war (row_count() < 1, alte ID in last_insert_id()).