Achot: MySQL Update durchführen

Hallo,

ein User kann bei mir eine Veranstaltung anlegen. Ich prüfe beim anlegen ob es diese Veranstaltung bereits gibt, dabei achte ich auf folgende Werte

  • Titel
  • Von
  • Bis

sind alle drei Werte gleich, kann das gleiche Projekt nicht noch einmal angelegt werden. Soweit so gut. Jetzt kommt mein Problem. Wenn ich die Werte bei

  • ar_kostensplittung
  • anzahl_kostensplittung

ändere, dann soll ein Update durchgeführt werden. Wie könnte ich dieses Problem angehen? Mein Code sieht folgendermaßen aus

$titel = $_POST["titel"];
$von   = $_POST["von"];
$bis   = $_POST["bis"];

$stmt = $mysqli->prepare("SELECT status, titel, von, bis, p_h_d, p_h_u, kostensplittung,
                                 anzahl_kostensplittung, name, vorname 
                          FROM projekte 
                          WHERE titel =? AND von =? AND bis =?");
    
    $stmt->bind_param("sss", $titel, $von, $bis);
    $stmt->execute();
    $stmt->store_result();
    $test =  $stmt->num_rows;
    $stmt->bind_result($status, $titel, $von, $bis, $p_h_d, $p_h_u, $kostensplittung,
                       $anzahl_kostensplittung, $name, $vorname);
    $stmt->fetch();
    $stmt->close();

    if ($test == 1) {
    	
    $errors[] = "Diese Veranstaltung wurde bereits von " . $vorname. " " . $name . " am " . $p_h_d . " um " . $p_h_u . " Uhr angelegt";
    
	}
	
  if(isset($_POST['abschicken']) && empty($errors)) {

		if(isset($_GET['code'])) {

		if ($stmt = $mysqli->prepare("
                                Update projekte SET titel=?, von=?, bis=?
                                       kostensplittung=?, anzahl_kostensplittung=? WHERE code = ?"))
		 {    
				$titel	 		= $_POST["titel"];
				$von		 	= $_POST["von"];
				$bis		 	= $_POST["bis"];
				$kostensplittung	= $_POST["kostensplittung"];
      			        $anzahl_kostensplittung	= $_POST["anzahl_kostensplittung"];
			

			$stmt->bind_param("ssssss",	
						$titel,
						$von,
						$bis,
						$kostensplittung, 
						$anzahl_kostensplittung,
						$code
		 );

	} } }

	$stmt->execute();
				header("Location: $headerLocation");
	}
				else {
						echo $mysqli -> error;
					}
	};
  1. Hi,

    ein User kann bei mir eine Veranstaltung anlegen. Ich prüfe beim anlegen ob es diese Veranstaltung bereits gibt, dabei achte ich auf folgende Werte sind alle drei Werte gleich, kann das gleiche Projekt nicht noch einmal angelegt werden. Soweit so gut. Jetzt kommt mein Problem. Wenn ich die Werte bei

    • ar_kostensplittung
    • anzahl_kostensplittung ändere, dann soll ein Update durchgeführt werden. Wie könnte ich dieses Problem angehen? Mein Code sieht folgendermaßen aus

    Stichworte: einen unique index auf die 3 Spalten, insert on duplicate key update

    cu,
    Andreas a/k/a MudGuard

    1. Ich passe ungern eine Fremde Tabelle an, wo noch andere Menschen mit dran arbeiten und Daten von extern eingespielt werden. Keine Ahnung was da passiert, wenn ich etwas umschalte.

      1. Hallo Achot,

        Ich passe ungern eine Fremde Tabelle an, wo noch andere Menschen mit dran arbeiten und Daten von extern eingespielt werden. Keine Ahnung was da passiert, wenn ich etwas umschalte.

        Ich würde eine sauber definierte API einbauen, die die Interna nach außen (für andere Mitarbeitende (Mitprogrammierende) und externe Daten) hin abstrahiert.

        Gruß
        Julius

        --
        „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
        Andrew S. Tanenbaum (Quelle)
        1. Hallo,

          löst jetzt auf die schnelle allerdings nicht mein Problem. Ich habe den oben genannten Code und muss daraus jetzt erst einmal das beste machen.

        2. Eine Idee:

          Ich muss diesen Wert

          $errors[] = "Diese Veranstaltung wurde bereits von " . $vorname. " " . $name . " am " . $p_h_d . " um " . $p_h_u . " Uhr angelegt";
          

          nicht als Error kennzeichnen, sondern also z.B. Hinweis

          $hinweis[] = "Diese Veranstaltung wurde bereits von " . $vorname. " " . $name . " am " . $p_h_d . " um " . $p_h_u . " Uhr angelegt";
          

          und Innerhalb von Update muss ich hier

          $titel	 		= $_POST["titel"];
          $von		 	= $_POST["von"];
          $bis		 	= $_POST["bis"];
          

          prüfen, ob in $hinweis[] etwas steht, wenn ja, muss ich die Felder aus dem Update heraus nehmen und nur ein Update mit

          $kostensplittung	= $_POST["kostensplittung"];
          $anzahl_kostensplittung	= $_POST["anzahl_kostensplittung"];
          

          machen. Bin ich auf dem richtigen Weg?

          1. Hallo,

            ich habe meine drei Spalten mit einem unique index versehen. Mein Code lautet nun so

            if ($stmt = $mysqli->prepare("INSERT INTO projekte_test (code, status, titel, userID, von, bis, h_d, h_u, del, kostensplittung, anzahl_kostensplittung)  
            	VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE kostensplittung = kostensplittung, anzahl_kostensplittung = anzahl_kostensplittung"))
            	{    
            			 
            		$code		= $projekt_Code;
            		$status		= "1";
            		$titel		= $_POST["titel"];
            		$userID		= $object->user_code;
            		$von 		= $_POST["von"];
            		$bis 		= $_POST["bis"];
            		$h_d      	= date("d.m.Y");
                  	$h_u   			= date("H:i:s");
                  	$del			= "0";
                  	$kostensplittung	= $_POST["kostensplittung"];
                  	$anzahl_kostensplittung	= $_POST["anzahl_kostensplittung"];
            				
            		$stmt->bind_param("sssssssssss", $code, $status, $titel, $userID, $von, $bis, $h_d, $h_u, $del, $kostensplittung, $anzahl_kostensplittung);
            	}
            

            Einen neuen Eintrag kann ich machen, ein doppelten lässt er nicht so, aber er macht kein Update. Irgendwo ist noch der Fehler. Seht ihr ihn vielleicht?

            EDIT: Ich bin ja auch ein trottel. Muss natürlich so lauten

            ON DUPLICATE KEY UPDATE kostensplittung = kostensplittung + VALUES(kostensplittung), anzahl_kostensplittung = anzahl_kostensplittung + VALUES(kostensplittung)
            

            EDIT2:

            • VALUES ist scheinbar falsch, denn da zählt er den Wert einfach nach oben und ersetzt diese nicht. Hmm da muss was anderes stehen.
            1. Es geht scheinbar so

              ON DUPLICATE KEY 
              UPDATE kostensplittung = kostensplittung  + VALUES = $_POST["kostensplittung"], 
               anzahl_kostensplittung = anzahl_kostensplittung  + VALUES = $_POST["anzahl_kostensplittung"]
              

              Jetzt erhalte ich allerdings folgende Meldung

              Parse error: syntax error, unexpected '"', expecting identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING)

              Irgendetwas stimmt mit $_POST["kostensplittung"] nicht.

              1. hallo

                Irgendetwas stimmt mit $_POST["kostensplittung"] nicht.

                All Userinput is evil! Was hast du unternommen, um das Gegenteil zu beweisen?

                1. ? Was willst du mir damit sagen? Kann es sein, dass du selber nicht weißt wo der Fehler ist und einfach irgendein Kommentar abgeben willst?

                  1. hallo

                    ? Was willst du mir damit sagen?

                    In keinem deiner Script-Ausschnitte habe ich auch nur den Hauch einer input-Validierung gesehen. Als typische Gutmensch gehe ich immer noch davon aus, dass du das bereits gemacht hast.

                    1. Das hat nichts, aber auch gar nichts mit meinem aktuellen Problem zu tun. Außerdem übernimmt $stmt = $mysqli->prepare diese ganze Sachen.

                      1. Hallo Achot,

                        Das hat nichts, aber auch gar nichts mit meinem aktuellen Problem zu tun. Außerdem übernimmt $stmt = $mysqli->prepare diese ganze Sachen.

                        Wenn du die Query so zusammenbaust, wie du sie oben zeigst zeigst, nicht. Falls du einfach zu Demonstrationszwecken die $_POST[]s in die Query eingebaut hast, um nicht den kompletten Quellcode hier hinein kopieren zu müssen, solltest du lieber etwas mehr Quelltext zeigen.

                        Gruß
                        Julius

                        --
                        „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                        Andrew S. Tanenbaum (Quelle)
                        1. Jetzt mal im erst, rede ich Japanisch? Ich wollte das $_POST einbauen, aber es FUNKTIONIERT nicht, warum soll ich mich dann mit irgendwelchen Sicherheitsmaßnahmen beschäftigen?

                          Hab es auch schon so versucht

                          ON DUPLICATE KEY 
                          UPDATE kostensplittung = kostensplittung  + ?, 
                          anzahl_kostensplittung = anzahl_kostensplittung  + ?
                          

                          Auch das geht leider nicht.

                          1. Moin!

                            ON DUPLICATE KEY 
                            UPDATE kostensplittung = kostensplittung  + ?, 
                            anzahl_kostensplittung = anzahl_kostensplittung  + ?
                            

                            Auch das geht leider nicht.

                            Wie sieht denn die Fehlermeldung (ich glaube nicht, dass PHP in diesem Zusammenhang einen Syntaxfehler bemängeln wird...) bzw. die daraus zusammengebaute SQL-Query aus?

                            Gruß
                            Julius

                            --
                            „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                            Andrew S. Tanenbaum (Quelle)
                            1. Die habe ich oben doch bereits mit veröffentlicht

                              Parse error: syntax error, unexpected '"', expecting identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING)

                              1. Hallo Achot,

                                Die habe ich oben doch bereits mit veröffentlicht

                                Parse error: syntax error, unexpected '"', expecting identifier (T_STRING) or variable (T_VARIABLE) or number (T_NUM_STRING)

                                In diesem Code steckt aber kein PHP – warum sollte PHP dann einen Syntax-Fehler werfen?

                                ON DUPLICATE KEY 
                                UPDATE kostensplittung = kostensplittung  + ?, 
                                anzahl_kostensplittung = anzahl_kostensplittung  + ?
                                

                                Wenn PHP in beiden Fällen ($_POST direkt in der Query und Prepared Statement) diese Fehlermeldung wirft, hast du wohl etwas verkehrt gemacht, was im obigen Dreizeiler nicht enthalten ist.

                                Gruß
                                Julius

                                --
                                „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                                Andrew S. Tanenbaum (Quelle)
                                1. Das ganze sieht derzeit so aus

                                  if ($stmt = $mysqli->prepare('INSERT INTO projekte_test (code, status, titel, userID, von, bis, h_d, h_u, del, kostensplittung, anzahl_kostensplittung)  
                                  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 
                                  ON DUPLICATE KEY 
                                  UPDATE kostensplittung = kostensplittung  + VALUES = $_POST["kostensplittung"], 
                                   anzahl_kostensplittung = anzahl_kostensplittung  + VALUES = $_POST["anzahl_kostensplittung"]'))
                                  			 {    
                                  			 
                                  				$code					= $projekt_Code;
                                  				$status					= "1";
                                  				$titel					= $_POST["titel"];
                                  				$userID					= $object->user_code;
                                  				$von 					= $_POST["von"];
                                  				$bis 					= $_POST["bis"];
                                  				$h_d      				= date("d.m.Y");
                                        			$h_u   					= date("H:i:s");
                                        			$del					= "0";
                                        			$kostensplittung		= $_POST["kostensplittung"];
                                        			$anzahl_kostensplittung	= $_POST["anzahl_kostensplittung"];
                                  				
                                  				$stmt->bind_param("sssssssssss", $code, $status, $titel, $userID, $von, $bis, $h_d, $h_u, $del, $kostensplittung, $anzahl_kostensplittung);
                                  		}
                                  
                                  

                                  Und jetzt erhalte ich folgende Meldung

                                  Fatal error: Call to a member function execute() on a non-object in

                                  1. Hallo Achot,

                                    Und jetzt erhalte ich folgende Meldung

                                    Fatal error: Call to a member function execute() on a non-object in

                                    In deinem Quelltext ist aber kein execute() zu finden. Ich vermute mal, dass du entweder die Datenbankverbindung nicht initialisert hast, oder einen Tippfehler im Variablennamen mit dem PDO-Objekt hast. Schau dir mal die Beispiele im PHP-Manual an, vielleicht siehst du dann den Fehler, warum $var->execute() nicht funktioniert, wenn $var kein Objekt enthält.

                                    Gruß
                                    Julius

                                    --
                                    „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                                    Andrew S. Tanenbaum (Quelle)
                                    1. Sorry, habe ich vergessen. Dieses ist der Abschluss

                                      $stmt->execute();
                                      header("Location: $extra");
                                      

                                      Wenn ich dieses nutze, funktioniert es wunderbar

                                      ON DUPLICATE KEY UPDATE kostensplittung = kostensplittung + VALUES(kostensplittung), anzahl_kostensplittung = anzahl_kostensplittung + VALUES(kostensplittung)
                                      

                                      Mur wenn ich die $_POST Variable nehme, dann kommt es zu dieser Fehlermeldung. Ich glaube, ich verzichte auf das ON DUPLICATE. Da nutze ich lieber mehrere Updates und reagiere darauf.

                                      1. Hallo Achot,

                                        Sorry, habe ich vergessen. Dieses ist der Abschluss

                                        $stmt->execute();
                                        header("Location: $extra");
                                        

                                        Prüfe mal ob er in dieses if ($stmt = $mysqli->prepare('INSERT INTO projekte_test (code, status […]')) überhaupt rein geht. Wenn nicht, geht $stmt->execute(); natürlich schief, weil $stmt kein Objekt enthält.

                                        Wenn ich dieses nutze, funktioniert es wunderbar

                                        ON DUPLICATE KEY UPDATE kostensplittung = kostensplittung + VALUES(kostensplittung), anzahl_kostensplittung = anzahl_kostensplittung + VALUES(kostensplittung)
                                        

                                        Mur wenn ich die $_POST Variable nehme, dann kommt es zu dieser Fehlermeldung. Ich glaube, ich verzichte auf das ON DUPLICATE. Da nutze ich lieber mehrere Updates und reagiere darauf.

                                        Dann baust du das wohl falsch zusammen, sodass PHP meckert. Meinst du mit dem Verwenden von $_POST[] diese Passage hier?

                                        $code					= $projekt_Code;
                                        $status					= "1";
                                        $titel					= $_POST["titel"];
                                        $userID					= $object->user_code;
                                        $von 					= $_POST["von"];
                                        $bis 					= $_POST["bis"];
                                        

                                        Gruß
                                        Julius

                                        --
                                        „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                                        Andrew S. Tanenbaum (Quelle)
                                        1. Dann baust du das wohl falsch zusammen, dass PHP meckert. Meinst du mit Verwenden von $_POST[…] diese Passage hier?

                                          Nein, so wie in meinem ersten Posting. Ich sitze jetzt seit 5 Stunden an diesem Problem, mir vergeht es so langsam. Ich trennen mein INSERT und UPDATE einfach auf und mache mehrere Seite darauf.

                                          1. Hallo Achot,

                                            Dann baust du das wohl falsch zusammen, dass PHP meckert. Meinst du mit Verwenden von $_POST[…] diese Passage hier?

                                            Nein, so wie in meinem ersten Posting.

                                            Im ersten Beitrag machst du das gleich zweimal.

                                            Ich sitze jetzt seit 5 Stunden an diesem Problem, mir vergeht es so langsam.

                                            Du springst hin und her und mir (vielleicht dir auch nicht mehr) ist nicht mehr ganz klar, was eigentlich wie zusammenhängt. Hast du das, was ich hier über den Fehler mit dem „non-object“ schrieb, berücksichtigt?

                                            Also nochmal ganz in Ruhe (mach vielleicht auch mal eine Pause) von Anfang an:

                                            1. Die SQL-Query für sich macht, was du willst (scheinst du ja in phpMyAdmin oder so getestet zu haben). Das ist gut, weil ich die nicht verstehe 😀
                                            2. Dein PHP-Script macht Ärger.
                                            3. Du nutzt Prepared Statements

                                            Vorgehen:

                                            1. Simpelst mögliches PHP mit einer ganz simplen Query und ein paar Parametern bauen und lauffähig bekommen.
                                            2. Deine fertige SQL-Query da rein packen, funktionierts jetzt?
                                            3. Alles Weggelassenes wieder einfügen.

                                            Ein paar Tipps zum Stil (bitte nicht übel nehmen):

                                            Du solltest das Umkopieren von Variablen vermeiden (sofern du sie nicht verändern willst und die originalen in $_POST behalten willst), außer Speicherverbrauch erhöhen, mehr Quelltext und schlechterem Überblick hat man nichts davon.

                                            Also statt:

                                            $code					= $projekt_Code;
                                            $status					= "1";
                                            $titel					= $_POST["titel"];
                                            $userID					= $object->user_code;
                                            $von 					= $_POST["von"];
                                            $bis 					= $_POST["bis"];
                                            
                                            $stmt->bind_param("sssssssssss", $code, $status, $titel, $userID, $von, $bis, $h_d, $h_u, $del, $kostensplittung, $anzahl_kostensplittung);
                                            

                                            ... lieber dieses:

                                            $stmt->bind_param("sssssssssss",
                                               $projekt_Code,
                                               1, //status
                                               $_POST["titel"],
                                               $object->user_code,
                                               // ... 
                                            );
                                            

                                            Falls die Variablenbezeichner nicht sprechend sind, solltest du das ändern oder als Workaround einen Kommentar dahinter packen. Da der Wert „Status“ im Script selbst zu stehen scheint und ein Integer ist, kannst du ihn ggf. auch direkt in die Query schreiben.

                                            Außerdem würde ich an deiner Stelle auch Leerzeichen zur Einrückung setzen, zwei Tabulatoren sehen hier im Forum einfach schlecht aus...

                                            Gruß
                                            Julius

                                            --
                                            „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                                            Andrew S. Tanenbaum (Quelle)
                                            1. Danke für deine lange Antwort, aber wir reden aneinander vorbei und ich bin eh schon so genervt dass ich über 5 Stunden an einem scheiß Script sitze. Es funktioniert, alle Variablen sind richtig, sonst würde es in meinem Ausgangscode ja auch nicht funktionieren, oder? Also kann es daran nicht liegen.

                                              Und ich möchte gerne die Werte umkopieren, ich für mich kann den Code dann besser lesen. Aber auch daran kann es nicht liegen. So arbeite ich schon von Anfang an.

                                              1. Hallo Achot,

                                                Danke für deine lange Antwort, aber wir reden aneinander vorbei und ich bin eh schon so genervt dass ich über 5 Stunden an einem scheiß Script sitze.

                                                Das Gefühl hatte ich auch und habe deshalb auch versucht, das etwas zu sortieren, aber du gehst ja auch immer nur auf Teilaspekte ein (ob er wirklich ins if reingeht, ob meine Annahmen stimmen), so macht das keinen Spaß.

                                                Wenn man zu lange an einem Problem sitzt, sieht man oft die Lösung nicht, bevor man dem Ganzen einen längeren Augenblick den Rücken zugekehrt hat.

                                                Es funktioniert, alle Variablen sind richtig, sonst würde es in meinem Ausgangscode ja auch nicht funktionieren, oder? Also kann es daran nicht liegen.

                                                Zu den Variablen habe ich ja auch nichts gesagt (außer die Empfehlungen zur Vormatierung). Der Fehler liegt, wie ich bereits oft genug gesagt habe, wohl darin, dass du die execute-Methode eines Objekts aufzurufen versuchst, das keins ist. Wenn eine Variable kein Objekt enthält, hast du ihr keins zugewiesen, aber das lässt sich mit dem Quellcode-Ausschnitt nicht feststellen. Daher auch mein Vorschlag, ein lauffähiges minimal-Beispiel zu erstellen.

                                                Und ich möchte gerne die Werte umkopieren, ich für mich kann den Code dann besser lesen.

                                                Wenn du mit sinnvollen Variablennamen arbeitest und auch mal im Funktionsaufruf umbrichst, ist er das auch bei dieser Variante so.

                                                Aber auch daran kann es nicht liegen. So arbeite ich schon von Anfang an.

                                                Dass das die Ursache des Fehlers sei, habe ich auch nicht behauptet, sondern nur eine Best-Practice aufgezeigt. Du siehst immer, woher welcher Wert kommt (z. B. aus POST) und kannst entsprechend mit ihnen umgehen. Außerdem ist es halt kürzer und etwas performanter.

                                                Natürlich kommt man manchmal nicht ums Umkopieren herum, beispielsweise weil man den Wert im POST ändern möchte, aber gleichzeitig das Original behalten möchte.

                                                Gruß
                                                Julius

                                                --
                                                „Unterschätze niemals die Datenübertragungsrate eines mit Bändern vollgeladenen Kombis, der über die Autobahn rast.“
                                                Andrew S. Tanenbaum (Quelle)
                          2. Hi,

                            Jetzt mal im erst, rede ich Japanisch? Ich wollte das $_POST einbauen, aber es FUNKTIONIERT nicht, warum soll ich mich dann mit irgendwelchen Sicherheitsmaßnahmen beschäftigen?

                            Hab es auch schon so versucht

                            ON DUPLICATE KEY 
                            UPDATE kostensplittung = kostensplittung  + ?, 
                            anzahl_kostensplittung = anzahl_kostensplittung  + ?
                            

                            Hast Du denn dem bind_param dann auch 2 zusätzliche Werte übergeben für die zwei zusätzlichen Fragezeichen?

                            Da Du leider immer nur kleine Teile Deines Codes zeigst, ist nicht wirklich nachvollziehbar, was bei welchem Deiner zahllosen Rate-Versuche tatsächlich passiert.

                            Du solltest Dir vielleicht mal das Handbuch zu den von Dir verwendeten Sachen durchlesen. Weil mehrere Stunden planlose Rateversuche locker 10 Minuten Handbuchlesen ersparen können.

                            cu,
                            Andreas a/k/a MudGuard

                            1. Hallo,

                              ich habe hier bereits den ganzen Code gepostet. Aber nein, natürlich habe ich mein bind_param nicht erweitert :/ Ich dachte da dieses die gleiche Werte sind wie oben ist dieses nicht nötig 😕

                              1. Jedes Fragezeichen muss separat gebunden werden.

                                Wenn Du einen einmal gebundenen Parameter an mehreren Stellen verwenden willst, brauchst Du benannte Parameter, das kann mysqli nicht, das kann nur PDO.

                                Du hättest aber durchaus auch deine POST-Variablen verwenden können. Das Problem war, dass PHP Variablen in Strings nur dann auflöst, wenn der String in doppelten Anführungszeichen steht oder ein heredoc-String ist.

                                $gruss = "Hallo";
                                echo "$gruss Welt";   // --> Hallo Welt
                                echo '$gruss Welt';   // --> $gruss Welt
                                

                                Für dich also z.B. so. Bei einem int-Parameter kann man intval gegen Injektionsattacken nehmen, einen Stringparameter musst Du binden oder real-escapen.

                                $id = intval($_POST['id']);
                                $sql = "SELECT * FROM TABLE WHERE ID=$id";
                                

                                Rolf