Jnnbo: $mysqli->insert_id wird nicht übernommen

Moin,

ich verstehe es einfach nicht. Mein zweites Insert wird zwar ausgeführt aber der Wert "$ps_pTypID" nicht übernommen. In der Datenbank steht eine 0

if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
{    
  $py_titel 	= $_POST["titel"];
  $py_status 	= $_POST["status"];
  
  $stmt->bind_param("ss", $py_titel, $py_status);
  $stmt->execute();
}
  else {
  echo $mysqli -> error;
}

if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings (ps_pTypID) VALUES (?)"))
{    
  $ps_pTypID 	= $mysqli->insert_id;

  $stmt->bind_param("s", $ps_pTypID);
  $stmt->execute();
  echo $ps_pTypID;
}
else {
  echo $mysqli -> error;
}

Genau dieser Code hat bis jetzt immer funktioniert. Ich habe damit hunderte von Einträge gemacht. Von jetzt auch gleich geht nichts mehr. Sehr ihr vielleicht den Fehler?

Wenn ich mir "$ps_pTypID" ausgeben lasse (siehe Script) dann wird auch die richtige id angezeigt. Meine errorLog bleibt leer.

akzeptierte Antworten

  1. Hallo und guten Morgen,

    Moin,

    ich verstehe es einfach nicht. Mein zweites Insert wird zwar ausgeführt aber der Wert "$ps_pTypID" nicht übernommen. In der Datenbank steht eine 0

    if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
    {    
      $py_titel 	= $_POST["titel"];
      $py_status 	= $_POST["status"];
      
      $stmt->bind_param("ss", $py_titel, $py_status);
      $stmt->execute();
    }
      else {
      echo $mysqli -> error;
    }
    
    if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings (ps_pTypID) VALUES (?)"))
    {    
      $ps_pTypID 	= $mysqli->insert_id;
    
      $stmt->bind_param("s", $ps_pTypID);
      $stmt->execute();
      echo $ps_pTypID;
    }
    else {
      echo $mysqli -> error;
    }
    

    Also abgesehen davon, dass mir der Sinn nicht klar ist, warum Du nur eine Insert-ID, alsoe einen Fremdschlüssel nochmal alleine (unter einem Eigenschlüssel?) in einer anderen Tabelle abspeichern willst, warum bleibst Du dann nicht in der Datenbank und nimmst LAST_INSERT_ID()?

    $stmt = $mysqli->prepare("INSERT INTO web_preis_settings set ps_pTypID = LAST_INSERT_ID()")
    

    Grüße
    TS

    1. Hallo TS,

      Also abgesehen davon, dass mir der Sinn nicht klar ist, warum Du nur eine Insert-ID, alsoe einen Fremdschlüssel nochmal alleine (unter einem Eigenschlüssel?)

      Der Hintergrund ist, dass ich zuerst ein Produkttyp anlegen muss, dazu gibt es später ein Preis und diverse %-Werte, die in einer anderen Tabelle stehen. Dass ich nichts vergesse trage ich in die neue zweite Tabelle lediglich die ID von dem aktuellen Eintrag ein, dass ich die Verknüpfung schon einmal habe.

      [...]dann nicht in der Datenbank und nimmst LAST_INSERT_ID()?

      Weil ich das bis jetzt immer nur mit $mysqli->insert_id; gelernt habe und wie gesagt die letzten Monate hat es damit auch ohne Probleme funktioniert. Hat sich an PHP diesbezüglich irgendetwas geändert, warum dieses auf einmal nicht mehr geht?

      Edit:

      OK, so funktioniert es wieder

      if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
      {    
        $py_titel 	= $_POST["titel"];
        $py_status 	= $_POST["status"];
        
        $stmt->bind_param("ss", $py_titel, $py_status);
        $stmt->execute();
      }
        else {
        echo $mysqli -> error;
      }
      
      if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings set ps_pTypID = LAST_INSERT_ID()"))
      {    
        $stmt->execute();
      }
      else {
        echo $mysqli -> error;
      }
      
      1. Hallo und guten Tag,

        [...]dann nicht in der Datenbank und nimmst LAST_INSERT_ID()?

        Weil ich das bis jetzt immer nur mit $mysqli->insert_id; gelernt habe und wie gesagt die letzten Monate hat es damit auch ohne Probleme funktioniert. Hat sich an PHP diesbezüglich irgendetwas geändert, warum dieses auf einmal nicht mehr geht?

        Warum das mit $mysqli->insert_id nicht funktioniert, kann ich mir auch nicht vorstellen. Das kann eigentlich nur passieren, wenn man zwischendurch mit der Connection oder dem Objekt etwas anderes anstellt.

        Ich würde das aber an deiner Stelle im Auge behalten. Wenn es nämlich ein Bug sein sollte (ist in den seltensten Fällen so...), dann könnten ja noch andere Seiteneffekte vorhanden sein.

        OK, so funktioniert es wieder

        if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
        {    
          $py_titel 	= $_POST["titel"];
          $py_status 	= $_POST["status"];
          
          $stmt->bind_param("ss", $py_titel, $py_status);
          $stmt->execute();
        }
          else {
          echo $mysqli -> error;
        }
        
        if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings set ps_pTypID = LAST_INSERT_ID()"))
        {    
          $stmt->execute();
        }
        else {
          echo $mysqli -> error;
        }
        

        Umkopieren der POST-Variablen ist nicht mehr notwendig. Wenn die "as it is" in die Datenbank sollen, kannst Du die direkt ins Bind einsetzen.

        Du musst übrigens sie Statements nicht immer neu preparen. Sosie die Verbindung steht, kannst Du die Statements, die Du immer brauchst, auch sammeln:

        $stmt['insert_id'] = $mysqli->prepare("INSERT INTO web_preis_settings set ps_pTypID = ?  
        $stmt['insert_prod] = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))  
        
        usw.
        

        Und dann brauchst Du nur noch die frischen Variablen an das passende Statement zu binden und das Query absenden. Das ist bei komplexeren Statements schon mal ganz praktisch.

        Grüße
        TS

        1. Hallo TS,

          Umkopieren der POST-Variablen ist nicht mehr notwendig. Wenn die "as it is" in die Datenbank sollen, kannst Du die direkt ins Bind einsetzen.

          das heißt aus diesem

          if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
          {    
            $py_titel 	= $_POST["titel"];
            $py_status 	= $_POST["status"];
            
            $stmt->bind_param("ss", $py_titel, $py_status);
            $stmt->execute();
          }
            else {
            echo $mysqli -> error;
          }
          

          kann ich auch dieses machen?

          if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
          {      
            $stmt->bind_param("ss", $_POST["titel"], $_POST["status"]);
            $stmt->execute();
          }
            else {
            echo $mysqli -> error;
          }
          

          Du musst übrigens sie Statements nicht immer neu preparen. Sosie die Verbindung steht, kannst Du die Statements, die Du immer brauchst, auch sammeln:

          $stmt['insert_id'] = $mysqli->prepare("INSERT INTO web_preis_settings set ps_pTypID = ?  
          $stmt['insert_prod] = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))  
          
          usw.
          

          Und dann brauchst Du nur noch die frischen Variablen an das passende Statement zu binden und das Query absenden. Das ist bei komplexeren Statements schon mal ganz praktisch.

          das habe ich leider nicht verstanden :7 Hast du mir da irgendeine Quelle? Oder kannst du mir dieses an meinem Beispiel nochmals genauer erklären, wie das Ergebnis dann aussehen würde?

          if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
          {      
            $stmt->bind_param("ss", $_POST["titel"], $_POST["status"]);
            $stmt->execute();
          }
            else {
            echo $mysqli -> error;
          }
          
          if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings (ps_pTypID) VALUES (?)"))
          {    
            $ps_pTypID 	= $mysqli->lastInsertId();
          
          $stmt->bind_param("s", $ps_pTypID);
            $stmt->execute();
          }
          else {
            echo $mysqli -> error;
          }
          
      2. Hallo und guten Morgen,

        [...]dann nicht in der Datenbank und nimmst LAST_INSERT_ID()?

        Weil ich das bis jetzt immer nur mit $mysqli->insert_id; gelernt habe

        Ich könnte mir vorstellen, dass es $stmt->insert_id heißen muss, da nach dem Execute eigentlich alle Ergebnisse über den $stmt-Ressource-Identifier angefasst werden müssen.

        Aber das kann und will ich jetzt nicht ausprobieren. Ich arbeite nicht mit PDO, weil ich mir mal unter viel Gegrübel eine OOP-Lösung ohne PDO gebastelt habe, die wesentlich mehr kann.

        Grüße
        TS

      3. Hallo und guten Abend,

        [...]dann nicht in der Datenbank und nimmst LAST_INSERT_ID()?

        Weil ich das bis jetzt immer nur mit $mysqli->insert_id; gelernt habe und wie gesagt die letzten Monate hat es damit auch ohne Probleme funktioniert. Hat sich an PHP diesbezüglich irgendetwas geändert, warum dieses auf einmal nicht mehr geht?

        Ich habe jetzt selber noch ein wenig gelesen, so ca. 50-60 verschiedene Seiten mit ca. 200 Meinugen und Tipps. Also die Mehrheit schreibt, dass es nicht um eine Property des Statement-Objektes handelt, sondern um eine Methode des Datenbankobjektes. Bei PHP steht, dass PDO::lastInsertId() nicht sicher funktioniert.
        http://php.net/manual/de/pdo.lastinsertid.php

        Ist eben alles nicht sauber entwickelt... Oder die haben sich einfach überrissen.

        Also müsste es nun mMn heißen: $pdo->lastInsertId() oder bei Dir eben $mysqli->lastInsertId()

        Grüße
        TS

        1. Hallo TS,

          Ich habe jetzt selber noch ein wenig gelesen, so ca. 50-60 verschiedene Seiten mit ca. 200 Meinugen und Tipps. Also die Mehrheit schreibt, dass es nicht um eine Property des Statement-Objektes handelt, sondern um eine Methode des Datenbankobjektes. Bei PHP steht, dass PDO::lastInsertId() nicht sicher funktioniert.
          http://php.net/manual/de/pdo.lastinsertid.php Ist eben alles nicht sauber entwickelt... Oder die haben sich einfach überrissen. Also müsste es nun mMn heißen: $pdo->lastInsertId() oder bei Dir eben $mysqli->lastInsertId()

          vielen lieben Dank nochmals für deine Hilfe, also müsste es so heißen?

          if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
          {    
            $py_titel 	= $_POST["titel"];
            $py_status 	= $_POST["status"];
            
            $stmt->bind_param("ss", $py_titel, $py_status);
            $stmt->execute();
          }
            else {
            echo $mysqli -> error;
          }
          
          if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings (ps_pTypID) VALUES (?)"))
          {    
            $ps_pTypID 	= $mysqli->lastInsertId();
          
          $stmt->bind_param("s", $ps_pTypID);
          $stmt->execute();
          }
          else {
            echo $mysqli -> error;
          }
          
          1. Hallo und guten Abend,

            Also müsste es nun mMn heißen: $pdo->lastInsertId() oder bei Dir eben $mysqli->lastInsertId()

            vielen lieben Dank nochmals für deine Hilfe, also müsste es so heißen?

            Ja, denke ich. Probier es doch bitte mal aus.

            if ($stmt = $mysqli->prepare("INSERT INTO web_produkttypen (py_titel, py_status) VALUES (?, ?)"))
            {    
              $py_titel 	= $_POST["titel"];
              $py_status 	= $_POST["status"];
              
              $stmt->bind_param("ss", $py_titel, $py_status);
              $stmt->execute();
            }
              else {
              echo $mysqli -> error;
            }
            
            if ($stmt = $mysqli->prepare("INSERT INTO web_preis_settings (ps_pTypID) VALUES (?)"))
            {    
              $ps_pTypID 	= $mysqli->lastInsertId();
            
            $stmt->bind_param("s", $ps_pTypID);
            $stmt->execute();
            }
            else {
              echo $mysqli -> error;
            }
            

            Wenn man nur mit MySQL arbeitet, ist PDO eindeutig überskaliert. Das könnte man doch nur wirklich brauchen, wenn man den Datenbanktreiber ständig wecheln muss und nicht immer seine Seite der API ändern will.

            Ein vernünftig durchdachtes Modul mit MySQLi, dass z.B. dann auch sinngemäße Konvertierungen und Prüfung von Typen übernimmt, das Escaping durchführt, usw. (das würde hier zu weit führen), reicht bestimmt in 95% der Anwendungsfälle.

            Sonst kann man auch ganz auf SQL verzichten, und gleich mit einem rudimentären bTrieve arbeiten. Das gibts schon 25 Jahre (seit Novell SLS->1) und es läuft.

            Grüße
            TS

            1. Tach!

              Wenn man nur mit MySQL arbeitet, ist PDO eindeutig überskaliert. Das könnte man doch nur wirklich brauchen, wenn man den Datenbanktreiber ständig wecheln muss und nicht immer seine Seite der API ändern will.

              Auch wenn man nur mit MySQL arbeitet ist PDO besonders bei den Prepared Statements anwenderfreundlicher als die MySQLi-Extension. Versuch mal eine Funktion zu schreiben, die als Parameter einen Statement-String und ein Array mit den Werten für die Platzhalter übernehmen soll, und die dann das Handling des Preparierens, Bindens (zweimal, Parameter und Rückgabewerte) und Ausführens nebst Fehlerbehandlung übernimmt, damit man das nicht tausendmal kopiert in seinem Program stehen hat. Man bricht sich dabei einen ab, weil der Bindingmechanismus auf einzelne Variablen und Referenzen darauf ausgelegt ist. Bei PDO kann man sich das Binding-Gehampel sparen und einfach beim Execute ein Array mit den Werten übergeben.

              Ein vernünftig durchdachtes Modul mit MySQLi, dass z.B. dann auch sinngemäße Konvertierungen und Prüfung von Typen übernimmt, das Escaping durchführt, usw. (das würde hier zu weit führen), reicht bestimmt in 95% der Anwendungsfälle.

              Was willst du bei Prepared Statements noch großartig konvertieren, typprüfen und maskieren? Für „95% der Anwendungsfälle“ ist PDO erfunden worden.

              dedlfix.

        2. Tach!

          Ich habe jetzt selber noch ein wenig gelesen, so ca. 50-60 verschiedene Seiten mit ca. 200 Meinugen und Tipps. Also die Mehrheit schreibt, dass es nicht um eine Property des Statement-Objektes handelt, sondern um eine Methode des Datenbankobjektes.

          PDO ist nicht MySQLi! Jnnbo verwendet kein PDO sondern die MySQLi-Extension. Und da ist insert_id eine Eigenschaft (keine Methode) beider Klassen, mysqli als auch mysqli_stmt.

          Bei PHP steht, dass PDO::lastInsertId() nicht sicher funktioniert.

          Das aber auch nur, weil der Mechanismus last_insert_id nicht in allen Datenbanksystemen vorhanden ist. Anderswo muss man stattdessen beispielsweise Sequenzen verwenden.

          Also müsste es nun mMn heißen: $pdo->lastInsertId() oder bei Dir eben $mysqli->lastInsertId()

          Nein. Seine Schreibweise war schon die für seinen Fall richtige. Warum allerdings nicht der richtige Wert eingetragen wird, kann ich auch nicht erkennen.

          dedlfix.

          1. Hallo dedlfix,

            Nein. Seine Schreibweise war schon die für seinen Fall richtige. Warum allerdings nicht der richtige Wert eingetragen wird, kann ich auch nicht erkennen.

            also mache ich erstmal alles wieder Rückgängig und schreibe morgen mal meinen Hoster an um zu fragen, ob er ein Update an der PHP Version gemacht hat (was er eigentlich sagen müsste)?