karl: wie die letzte ID einer mySQL-Tabelle auslesen?

Hallo,
ich habe eine mySQL Tabelle. Da gibt es das Feld "id" (typ: int(10), null:nein, extra:auto-increment).

Das Ganze wird eine mp3-Datenbank. Man trägt infos zu dem mp3 in eine Formular ein (Autor, Inhalt etc) und lädt gleichzeitig das entspr. mp3-file hoch. Mein PHP bastelt einen entspr. Namen für das mp3, bevor es abgespeichert wird (i.d.A. autor_titel_datum.mp3) Nun hätte ich im Namen noch gern die ID, mit der der entspr. Eintrag in mySQL gespeichert wird.

Wie krieg ich nun die aktuelle ID raus, BEVOR ich den Eintrag in die table einfüge? Zuerst wollte ich einen extra Zähler mitlaufen lassen, aber wenn dann irgendwann man was schieg geht (oder ein Eintrag aus der table gelöscht wird) gehts schon nicht mehr.

hat jemand eine idee?

vielen dank, karl m.

  1. Hallo,

    Wie krieg ich nun die aktuelle ID raus, BEVOR ich den Eintrag in die table einfüge? Zuerst wollte ich einen extra Zähler mitlaufen lassen, aber wenn dann irgendwann man was schieg geht (oder ein Eintrag aus der table gelöscht wird) gehts schon nicht mehr.

    Vorher gar nicht, aber direkt nach dem Insert.
    Siehe mysql_insert_id.

    lg
    Martin Dunst

    --
    Do what I say, not what I do.
    --Tim Berners-Lee
    1. Hallo Martin

      Wie krieg ich nun die aktuelle ID raus, BEVOR ich den Eintrag in die table einfüge? Zuerst wollte ich einen extra Zähler mitlaufen lassen, aber wenn dann irgendwann man was schieg geht (oder ein Eintrag aus der table gelöscht wird) gehts schon nicht mehr.

      Vorher gar nicht, aber direkt nach dem Insert.
      Siehe mysql_insert_id.

      Schade, weil dann ists schon zu spät :)
      Ich will den mp3-Dateinamen ja auch in die table eintragen und dazu brauch ich VOR dem Einfügen die ID. Geht das wirklich nicht?

      1. Hallo,

        Schade, weil dann ists schon zu spät :)
        Ich will den mp3-Dateinamen ja auch in die table eintragen und dazu brauch ich VOR dem Einfügen die ID. Geht das wirklich nicht?

        Nein, es geht wirklich nicht.
        Du wirst wohl ein Update nach dem Insert machen müssen.

        lg
        Martin Dunst

        --
        Do what I say, not what I do.
        --Tim Berners-Lee
        1. Hallo,

          Schade, weil dann ists schon zu spät :)
          Ich will den mp3-Dateinamen ja auch in die table eintragen und dazu brauch ich VOR dem Einfügen die ID. Geht das wirklich nicht?

          Nein, es geht wirklich nicht.
          Du wirst wohl ein Update nach dem Insert machen müssen.

          lg
          Martin Dunst

          Ok, vielen Dank für Deine Hilfe und gute Nacht!

          1. Hallo,

            Schade, weil dann ists schon zu spät :)
            Ich will den mp3-Dateinamen ja auch in die table eintragen und dazu brauch ich VOR dem Einfügen die ID. Geht das wirklich nicht?

            Nein, es geht wirklich nicht.
            Du wirst wohl ein Update nach dem Insert machen müssen.

            lg
            Martin Dunst

            Ok, vielen Dank für Deine Hilfe und gute Nacht!

            Sorry, doch noch eine Frage:
            Wie krieg ich denn mit einem mySQL Befehl heraus, welcher Eintrag der letzte ist? Weil ich will ja jeweils nur den updaten....

            danke nochmal
            Karl

            1. Sorry, doch noch eine Frage:
              Wie krieg ich denn mit einem mySQL Befehl heraus, welcher Eintrag der letzte ist? Weil ich will ja jeweils nur den updaten....

              Wie Du den letzten Eintrag kriegst wenn "Du in einer Verbindung sitzt", ist bereits beschrieben worden, ansonsten gibt es keinen letzten Eintrag.

              Du könntest, falls Du eine hochzählende ID hast, die Hochnummer als letzten Eintrag verstehen, aber für sowas wie "letzter Eintrag" nutzt man Zeitstempel.

              1. Hello,

                Du könntest, falls Du eine hochzählende ID hast, die Hochnummer als letzten Eintrag verstehen, aber für sowas wie "letzter Eintrag" nutzt man Zeitstempel.

                Nein, die letzte Insert-ID ist die richtige Größe. Das muss aber nicht unbedingt die größte Nummer in der entsprechenden Spalte (mit Autoincrement-Wert) sein. Das ist von DB zu DB unterschiedlich. Manche verteilen die Nummern auch chaotisch. Die letzte erteilte ist aber immer über "LAST_INSERT_ID()" erreichbar.

                Timestamps können bei schnellen Systemen auch zu Problemen führen, weil die Granularität des Timestamps zu grob ist für die Abarbeitungsgeschwindigkeit des Systems. Es können also leicht mehrere Datensätze mit demselben Timestamp entstehen, wenn man hier nicht Vorsorge betreibt (Uniqe)

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

                Tom

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

                1. Du könntest, falls Du eine hochzählende ID hast, die Hochnummer als letzten Eintrag verstehen, aber für sowas wie "letzter Eintrag" nutzt man Zeitstempel.

                  Nein, die letzte Insert-ID ist die richtige Größe. Das muss aber nicht unbedingt die größte Nummer in der entsprechenden Spalte (mit Autoincrement-Wert) sein. Das ist von DB zu DB unterschiedlich. Manche verteilen die Nummern auch chaotisch. Die letzte erteilte ist aber immer über "LAST_INSERT_ID()" erreichbar.

                  Verbindungsunabhängig?

                  Timestamps können bei schnellen Systemen auch zu Problemen führen, weil die Granularität des Timestamps zu grob ist für die Abarbeitungsgeschwindigkeit des Systems. Es können also leicht mehrere Datensätze mit demselben Timestamp entstehen, wenn man hier nicht Vorsorge betreibt (Uniqe)

                  Nichtsdestotrotz sind Zeitstempel die angewiesene Wahl.

                  1. Hello,

                    Nichtsdestotrotz sind Zeitstempel die angewiesene Wahl.

                    Nein!
                    Um einen Datensatz eindeutig identifizieren zu können, taugt der Zeitstempel nichts.
                    Ich kenne auch keine SQL-Funktion, die "Get Last Timestamp" heißt.
                    Last_Insert_ID() ist die einzige Funktion, mit der man ein Identifikationskriterium des letzten eingefügten Datensatzes erfragen kann. Wenn man das vergisst, und er sonst keine ID hat, findet man ihn auch nicht sicher wieder.

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

                    Tom

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

                    1. Nichtsdestotrotz sind Zeitstempel die angewiesene Wahl.

                      Nein!
                      Um einen Datensatz eindeutig identifizieren zu können, taugt der Zeitstempel nichts.
                      Ich kenne auch keine SQL-Funktion, die "Get Last Timestamp" heißt.
                      Last_Insert_ID() ist die einzige Funktion, mit der man ein Identifikationskriterium des letzten eingefügten Datensatzes erfragen kann. Wenn man das vergisst, und er sonst keine ID hat, findet man ihn auch nicht sicher wieder.

                      Die Fragestellung lautete:
                      --
                      https://forum.selfhtml.org/?t=145409&m=943683
                      "Wie krieg ich denn mit einem mySQL Befehl heraus, welcher Eintrag der letzte ist?"

                      Die richtige Antwort lautete:
                      --
                      https://forum.selfhtml.org/?t=145409&m=943685
                      "Wie Du den letzten Eintrag kriegst wenn "Du in einer Verbindung sitzt", ist bereits beschrieben worden, ansonsten gibt es keinen letzten Eintrag.

                      Du könntest, falls Du eine hochzählende ID hast, die Hochnummer als letzten Eintrag verstehen, aber für sowas wie "letzter Eintrag" nutzt man Zeitstempel."

                      Anmerkungen zu Deinem Tipp:
                      --
                      LAST_INSERT_ID() bedient eine Sitzung und gibt _nicht_ die zuletzt auf dem Datenserver in einer bestimmten Tabelle mit auto-increment eingefüpte ID zurück.

                      http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
                      "For LAST_INSERT_ID(), the most recently generated ID is maintained in the server on a per-connection basis. It is not changed by another client."
                      http://dev.mysql.com/doc/refman/4.1/en/information-functions.html
                      "The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own."

                      Schlussbemerkungen:
                      --
                      Darum eben Zeitstempel.   ;)

                      BTW - ausdrücklich unempfohlen werden soll an dieser Stelle erstens Abfragen gegen Systemtabellen zu senden und zweitens IDs (bspw. auto-increment) für irgendeinen Zweck auszuwerten, also ihnen irgendeine Bedeutung zu entziehen.

                      IDs sollen nur die Eindeutigkeit besorgen.

                      1. yo king schnully,

                        sicherlich muss last_insert_id nicht der letzte datensatz von der zeit her sein, der in die datenbank neu hinzugefügt wurde, da es ja session abhängig ist. aber der begriff "letzter" bezieht sich auch nicht immer auf eine zeitangabe. insofern bringt dir dein timestamp in bezug auf letzter reichlich wenig und man könnte stundenlang darüber streiten, was genau nun letzter bedeutet.

                        der springende punkt ist der, dass er genau diesen session-abhängigen "letzten" wert haben will und nicht den über den timestamp oder einem anderen kriterium für letzte. und da hat Tom vollkommen richtig klargestellt, dass die last_insert_id der richtige weg ist, um den datensatz zu bekommen, den ich mit meiner session als letztes eingefügt habe.

                        Ilja

                        1. sicherlich muss last_insert_id nicht der letzte datensatz von der zeit her sein, der in die datenbank neu hinzugefügt wurde, da es ja session abhängig ist. aber der begriff "letzter" bezieht sich auch nicht immer auf eine zeitangabe. insofern bringt dir dein timestamp in bezug auf letzter reichlich wenig und man könnte stundenlang darüber streiten, was genau nun letzter bedeutet.

                          Wie bereits geschrieben, den letzten Datensatz gibt es in absoluter Form nicht, allerdings könnte man im übertragenden Sinne den letzten Datensatz abrufen indem man sich eine nach einem Zeitstempel absteigend sortierte Datensatzmenge kommen lässt.

                          Dann hätte man den oder die Datensätze, die bis zu einem bestimmten Datum angelegt worden sind. Das ist durchaus Information.

                          Keine Information dagegegen hätte die Angabe des letzten Datensatzes, der angelegt worden ist. Selbst wenn man diesen mit einem serverübergreifenden Last_Insert_ID() abholen könnte, denn bereits zum Abfragezeitpunkt könnte die "Information" falsch sein.

                          Bei dieser Problematik geht es ein wenig ins Datenbankphilosophische.

                          Die Frage "Letzter eingefügte Datensatz auf einer Verbindung?" ist übrigens in diesem Rhread schon sehr früh beantwortet worden.

                          1. Hello,

                            Bei dieser Problematik geht es ein wenig ins Datenbankphilosophische.

                            Du verwirrst die Leute hier.
                            Denk bitte nochmal drüber nach, was der Sinn der eigentlichen Frage war.
                            https://forum.selfhtml.org/?t=145409&m=943676

                            Karl hat sehr genau beschrieben, was sein Anliegen ist.
                            Eine Lösung ist hierfür die von mir beschriebene
                            https://forum.selfhtml.org/?t=145409&m=943684

                            • Tabelle sperren
                            • Table-Status abfragen
                            • Next-Insert-ID holen
                            • Namen bilden für externe Daten
                            • Datensatz eintragen
                            • Tabelle entsperren

                            Ich habe ihm geantwortet, dass das ein Performance-Killer ist.
                            Außerdem haben "normale User" in üblichen Einrichtungen selten das LOCK TABLES Recht.
                            Das liegt aber daran, dass die "Administratoren" damit selten etwas anfangen können.

                            Alternativ habe ich ihm empfohlen, mittels LAST_INSERT_ID() zu arbeiten.
                            Und nun werde ich noch den Denkfehler beseitigen, den Karl mit dem Zeitverhalten seiner Anwendung hat:

                            • Datensatz mit MP3 hochladen
                                (Daten befinden sich nun in der Transfer-Area von PHP = im Temp-Verzeichnis)
                            • mit dem temp-File arbeiten, um z.B. die Kopfdaten auszulesen
                            • Datensatz zusammenstellen
                                (Achtung: auf eichtiges Escaping für die Datenbank achten)
                            • Datensatz abspeichern (mit Sperrvermerk oder Lock ausschließlich für den _Datensatz_)
                            • Last-Insert-Id holen
                            • Namen bilden für externe Daten (prüfen, ob der schon vorhanden ist?)
                            • File aus dem Temp-File unter dem verifizierten Namen abspeichern
                            • Update auf die DB, um den Sperrvermerk zu entfernen oder Unlock Record

                            Diese Lösung ist performant.
                            Sie benötigt keine Datei-Sperren.
                            Sie berücksichtigt die Write-Write-Lücke zwíschen den abhängigen Daten.

                            Wenn nämlich ein anderer Besucher den Datensatz aus der DB lesen würde, bevor die Datei wirklich abgespeichert wurde, würde sein MP3 leer sein, bzw. es gäbe einen File-Read-Error.

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

                            Tom

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

            2. Hello,

              Wie krieg ich denn mit einem mySQL Befehl heraus, welcher Eintrag der letzte ist? Weil ich will ja jeweils nur den updaten....

              Indem Du direkt nach dem Insert auf eine Tabelle über dieselbe Connection nach der Last Insert ID fragen lässt.

              http://dev.mysql.com/doc/internals/en/replication-auto-increment.html

              Es gibt auch eine PHP-Funktion hierfür, die aber leider nicht den vollen Wertevorrat des Schlüssels berücksichtigt, und daher bei größeren Schlüsseln fehlerhaft ist.

              http://www.php.net/manual/de/function.mysql-insert-id.php

              Also besser selbe eine Funktion bauen mittels SQL-Statement.

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

              Tom

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

    2. Hello,

      Vorher gar nicht,

      Das stimmt nicht, auch wenn Du aus üblicher Praxissicht Recht hast...

      Man kann den Tabellenstatus der gesamten Datenbank abfragen.
      In diesem sind dann auch die Next-Insert-IDs der Tabellen enthalten, die eine Autoincrement-Spalte besitzen.

      Wenn Du allerdings willst, dass das beim Insert noch stimmt, müsstest Du die entsprechende Tabelle sperren, dann die Status-Abfrage machen, den Datensatz einfügen und dann die Tabelle wieder entsperren. Das kostet sehr viel Performance.

      Darum macht man es i.d.R. umgekehrt. Man lässt den neuen Datensatz eintragen, beschafft dann die dazugehörige Insert-ID und arbeitet damit für die Related Infomation weiter.

      http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html
      http://dev.mysql.com/doc/refman/5.1/en/lock-tables.html

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

      Tom

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

      1. Hallo,

        Man kann den Tabellenstatus der gesamten Datenbank abfragen.
        In diesem sind dann auch die Next-Insert-IDs der Tabellen enthalten, die eine Autoincrement-Spalte besitzen.

        Stimmt, an diese (theoretische) Möglichkeit hatte ich nicht gedacht.

        lg
        Martin Dunst

        --
        Do what I say, not what I do.
        --Tim Berners-Lee
  2. echo $begrüßung;

    Mein PHP bastelt einen entspr. Namen für das mp3, bevor es abgespeichert wird (i.d.A. autor_titel_datum.mp3) Nun hätte ich im Namen noch gern die ID, mit der der entspr. Eintrag in mySQL gespeichert wird.

    Die ID ist doch sowieso schon im Datensatz enthalten. (Ebenso steht ".mp3" fest und müsste nicht nochmal gespeichert werden.) Du kannst beim Abfragen die Information aus der Namensspalte mit der ID (und dem ".mp3") verknüpfen. - Du könntest eigentlich alle Informationen im Dateinamen in einzelnen Feldern speichern und nur beim Abfragen zusammensetzen. (siehe Stringfunktionen, besonders CONCAT())

    echo "$verabschiedung $name";

    1. yo,

      Die ID ist doch sowieso schon im Datensatz enthalten. (Ebenso steht ".mp3" fest und müsste nicht nochmal gespeichert werden.) Du kannst beim Abfragen die Information aus der Namensspalte mit der ID (und dem ".mp3") verknüpfen.

      bei der id sehe ich das genauso, bei der dateiendung mp3 wäre ich vorsichtig, die nicht zu speichern und hart zu codieren. dann hätte man ein problem, wenn die endungen sich mal unterscheiden können.

      Du könntest eigentlich alle Informationen im Dateinamen in einzelnen Feldern speichern und nur beim Abfragen zusammensetzen. (siehe Stringfunktionen, besonders CONCAT())

      das hängt im wesentlichen davon ab, wie er die informationen später abruft. greift er nur auf den vollen namen zu, macht es meiner meinung keinen sinn, sie aufzusplitten. wenn er aber die einzelnen informationen im dateinamen auch über abfragen ansprechen will, dann macht eine aufteilung sinn, bzw. man könnte sogar redundante information speichern und beides miteinander kombinieren.

      Ilja

      1. Die ID ist doch sowieso schon im Datensatz enthalten. (Ebenso steht ".mp3" fest und müsste nicht nochmal gespeichert werden.) Du kannst beim Abfragen die Information aus der Namensspalte mit der ID (und dem ".mp3") verknüpfen.

        bei der id sehe ich das genauso,

        Ja, da habt ihr gleich das nächste datenbankphilosophische Fass aufgemacht. Die Fragestellung lautet: Wann berechnete Werte speichern?

        Hier lautet das Argument, dass die ID ohnehin verfügbar ist und so auf den Namen der logisch verzeigerten Datei geschlossen werden kann.

        Gleich zwei Argumente sprechen dagegen:
        1.) Wichtige Daten wie Dateinamen sind zu speichern, ggf. auch unter Inkaufnahme von Redundanz. Denn die Information ist sehr wichtig.
        Verstehen wird man das vielleicht, wenn man sich irgendwelche wichtige Vertragsdaten vorstellt, bspw. eine Mietrate, die aus anderen im selben Datensatz gespeicherten Werten berechnet wird.
        Stellen wir uns einfach mal vor, dass diese Rate auf einmal nicht stimmt. Dann tanzte der Bär!
        Noch lustiger vielleicht, wenn wir uns vorstellen, dass die Geschäftsregel zum Ermitteln der Rate (die ja nicht im DBDesign hinterlegt ist) nach einigen Jahren vergessen worden ist.   LOL
        Und die Dateinamensbildung, u.a. aus der ID, ist Geschäftslogik, die ebenfalls nicht hinterlegt ist. (OK, hier haben wir eine gewisse Einfachheit, aber wehret den Anfängen! ;)
        2.) Wird der dateinamen "just in time" mit Hilfe einer Regel wie oben beschrieben ermittelt, dann erhält die ID eine Bedeutung.
        IDs dürfen keine Bedeutung haben, das würde spätere administrative Datenarbeiten stark erschweren.

        Jetzt noch zur möglicherweise sich stellenden Frage: "Ist es denn OK, den Dateinamen mit der DatensatzID zu bilden?"
        Anwort: Ja, denn es handelt sich um die einmalige Anwendung einer Geschäftsregel, deren Anwendungsmethode vergessen werden darf.

        Du könntest eigentlich alle Informationen im Dateinamen in einzelnen Feldern speichern und nur beim Abfragen zusammensetzen. (siehe Stringfunktionen, besonders CONCAT())

        das hängt im wesentlichen davon ab, wie er die informationen später abruft. greift er nur auf den vollen namen zu, macht es meiner meinung keinen sinn, sie aufzusplitten. wenn er aber die einzelnen informationen im dateinamen auch über abfragen ansprechen will, dann macht eine aufteilung sinn, bzw. man könnte sogar redundante information speichern und beides miteinander kombinieren.

        Also, das wäre - wie oben beschrieben - alles Murks.