borisbaer: Update-Methode aktualisiert nicht die entsprechenden Spalten in der Datenbank (ohne Fehlermeldung)

Hallo zusammen,

ich habe folgenden Code in meiner Update-Methode …

protected function update( array $columns = [], array $condition = [] ): void

{

	$table = $this -> getTable();

	$attrs = array_merge( $columns, $condition );

	$columns = implode( ' AND ', array_map( fn( $attr ) => "$attr = :$attr", $columns ) );

	$condition = implode( ' AND ', array_map( fn( $attr ) => "$attr = :$attr", $condition ) );

	$stmt = self::prepare( "UPDATE $table SET $columns WHERE $condition" );

	foreach ( $attrs as $attr )

		$stmt -> bindValue( ":$attr", $this -> { $attr } );

	$stmt -> execute();

}

... und rufe sie bspw. so auf …

$games -> update( [ 'franchise' ], [ 'gameID' ] );.

Wenn ich den columns-Array um einen zusätzlichen String ergänze, z. B. so ...

$games -> update( [ 'franchise', 'platform' ], [ 'gameID' ] );

... dann aktualisiert die Methode die entsprechenden Spalten in der Datenbank nicht bzw. wird beim angegeben Eintrag für franchise eine 0 gesetzt und platform bleibt unverändert. Bei nur einem String im Array funktioniert das Update übrigens.

Ich verstehe beim besten Willen nicht, was da schiefläuft.

Was übersehe ich?

Grüße
Boris

akzeptierte Antworten

  1. Hallo alle - dies ist eine Aufgabe an borisbaer. Nicht vorsagen 😉

    Hallo borisbaer,

    (ohne Fehlermeldung)
    Was übersehe ich?

    Die Fehlermeldung. Da muss eine sein. Dein generiertes SQL ist in dem von Dir beschriebenen Schlecht-Fall definitiv falsch.

    Und Du übersiehst, dass man grundsätzlich SQL Fehlercodes prüfen und im Fehlerfall das generierte SQL zusammen mit allen verfügbaren Fehlerinformationen loggen muss. Dann weißt Du, was faul ist. Wenn nicht, kann ein Blick ins SQL Handbuch lehrreich sein.

    Fehlermeldungen kann es nach jedem API Aufruf geben. Ob deine nach prepare() oder execute() kommt, weiß ich grad nicht. Einer von beiden geht schief.

    Du könntest auch PDO::ATTR_ERRMODE auf PDO::ERRMODE_EXCEPTION setzen. Das geht auf jeden Fall im PDO-Konstruktor. Es geht auch mit der setAttribute-Methode. Ob es auch als $options-Parameter im prepare-Aufruf geht, weiß ich jetzt nicht. Mit dem EXCEPTION-Modus kannst Du den ganzen Block von prepare bis execute in einen einzigen try/catch einpacken und weißt, dass Du bei Fehlern automatisch in den catch-Teil fliegst. Das spart Dir die ständigen Fehlerabfragen.

    Nebenbei 1: In generiertem SQL sollte man Tabellen- und Spaltennamen in Backticks einschließen

    Nebenbei 2: Du solltest auch keine Defaultwerte für $columns und $conditions vorgeben. Ein leeres Array dürfte für beide Parameter keinen Sinn ergeben. Du solltest statt dessen eine Abfrage einbauen, ob mindestens ein Eintrag drin ist.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      Und Du übersiehst, dass man grundsätzlich SQL Fehlercodes prüfen und im Fehlerfall das generierte SQL zusammen mit allen verfügbaren Fehlerinformationen loggen muss. Dann weißt Du, was faul ist. Wenn nicht, kann ein Blick ins SQL Handbuch lehrreich sein.

      ich erhalte für gewöhnlich Fehlermeldungen, wenn es Probleme mit dem SQL-Code bzw. der Datenbank gibt. Auch steht bei mir im Conctructor der Datenbank bereits $this -> pdo -> setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );. Mir scheint, da ist nicht das Problem.

      Nebenbei 1: In generiertem SQL sollte man Tabellen- und Spaltennamen in Backticks einschließen

      Das habe ich ergänzt, wobei es auch ohne klappt.

      Nebenbei 2: Du solltest auch keine Defaultwerte für $columns und $conditions vorgeben. Ein leeres Array dürfte für beide Parameter keinen Sinn ergeben. Du solltest statt dessen eine Abfrage einbauen, ob mindestens ein Eintrag drin ist.

      Das ist deshalb drin, weil die Klasse bei nicht definierten columns-Parametern sämtliche in der Klasse vorgegeben Spalten aktualisiert.

      Ich denke, ich bekomme keine Fehlermeldung, weil es evtl. kein Fehler ist, sondern es einfach anders funktioniert, als ich es beabsichtige. Immerhin wird ja etwas aktualisiert, aber nicht richtig. Der erste Wert wird immer zu einer „0“. Der zweite bleibt gleich. Das heißt ja, eine Aktualisierung hat stattgefunden, nicht? 🤔

      Grüße
      Boris

      1. Hallo borisbaer,

        Du generierst

        UPDATE tabelle SET foo=:foo AND bar=:bar WHERE baz=:baz AND moo=:moo
        

        und das ist in meinem Buch falsches SQL.

        Wenn das bei Dir keinen Fehler wirft: hast Du vielleicht schlunzig kopiert und dein Code sieht anders aus als das, was Du gepostet hast?

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hi,

          UPDATE tabelle SET foo=:foo AND bar=:bar WHERE baz=:baz AND moo=:moo
          

          und das ist in meinem Buch falsches SQL.

          falsch ist es nicht. Es tut nur was anderes als das, was vermutlich beabsichtigt ist.

          Ich ergänze mal Klammern, damit man sieht, was dabei passiert:

          UPDATE tabelle SET foo= ( :foo AND bar=:bar ) WHERE baz=:baz AND moo=:moo
          

          Beabsichtigt ist vermutlich

          UPDATE tabelle SET foo=:foo, bar=:bar WHERE baz=:baz AND moo=:moo
          

          cu,
          Andreas a/k/a MudGuard

          1. Hallo MudGuard,

            autsch. Auf diese Idee wäre ich jetzt nicht gekommen. Das erklärt jedenfalls die 0.

            Rolf

            --
            sumpsi - posui - obstruxi