-1

I'm having an issue with the PDO Statement "Update". I want to update existing columns in my DB using this code:

<?php
$sql="UPDATE $title SET header = $header;";

for($co=1,$arr=0;$co<=$count;$co++,$arr++)
{
   $sql .= "UPDATE $title SET theme$co = :theme, content$co = :content;";
   $insert = array('theme' => $theme[$arr], 'content' => $content[$arr]); 

   $statement = $pdo->prepare($sql);
   $statement->execute($insert);
}
?>

The Problem is, that nothing happends in the DB when this code is done. The arrays "theme" & "content" just contain a bit of text which a user has written down to it. Depending on how many themes/content the user has entered the more arrays you get. For example:

$theme1="a";
$theme2="b";
$content1="abc";
$content2="def";

So in the DB, the colums were already created with the same names as the theme & content arrays. Now what I want to do is, insert the value of for example $theme1 to the column "theme1" and the same thing with $content1 to the column "content1" and so on...

I've already tried to change the

$sql .= to $sql =

and execute it as a single query. But that also didn't work.

I'm not using the "Insert" Statement, because it would always create a new line in the DB, so it would look like this.
As you can see on the screenshot this is completely wrong and I'm trying to get everything in one line. That's why I try Update instead of Insert. Since the creation of the table and all it's columns is working fine with PDO, I'm wondering why Update isn't working at all.

Edit: The variable "titel" isn't spelled wrong, I'm german and this is correct for me. Since you can name variables as you want, I'm allowed to do that in my mother language. But thanks anyway for telling me, i tried to replace all german variables with english words but I missed that one, so i've changed that now.

frosty
  • 49
  • 1
  • 2
  • 12
  • 2
    this at beginning of code $sql="UPDATE $titel SET header = $header;"; followed by this $sql .= "UPDATE $titel SET theme$co = :theme, content$co = :content;"; in the for loop will probably cause mysql exception because that first update statement isnt valid – victor Sep 06 '17 at 14:45
  • Check your spelling on the variable `$titel`. Should it be `$title`? – Aaron K. Sep 06 '17 at 14:46
  • 1
    [Ensure that error reporting is enabled to help you debug.](https://stackoverflow.com/questions/32648371/my-pdo-statement-doesnt-work) – Script47 Sep 06 '17 at 14:46
  • @AaronK. nope, OP has spelt it wrong in both places. – Script47 Sep 06 '17 at 14:48
  • I'd guess `$sql="UPDATE $titel SET header = $header;";` is invalid (should be parameterized and unquoted string), and why execute the same update X times? – chris85 Sep 06 '17 at 14:49
  • 1
    Multiple UPDATE in single query is invalid . Ye you can do multiple update of values in single query but using multiple time `UPDATE` keyword in single query is invalid – Alive to die - Anant Sep 06 '17 at 14:50
  • even once they're executed properly, all these updates in the loop are just going to overwrite each other because there's no WHERE clause, so it updates every DB row each time with the same values. So you'll just end up with all rows having the values of whatever was in the last UPDATE to be run. – ADyson Sep 06 '17 at 14:59
  • It wont replace the value of the columns over and over. Each loop-run the counter $arr gets incremented , so the code would write the array value of field 1 instead of field 0. The same thing with the counter $co. – frosty Sep 06 '17 at 15:09
  • ok so you have columns theme1, content1, theme2, content2? That's a badly denormalised design. You need one more table, with a foreign key between the table represented by $title and the new one. – ADyson Sep 06 '17 at 15:27
  • Yes i know. I will defenitely work on that. But this doesn't solve my problem. I've tried the update query in phpmyadmin, it says Success, 0 Records affected. – frosty Sep 06 '17 at 15:54
  • which of the two statements are you referring to? And if the second one, which version of it? Have you actually got any rows in your table to update? – ADyson Sep 06 '17 at 19:47

1 Answers1

0

Here is my solution. It contains error reporting/display and all the proper steps involved in using PDO prepared statements in combination with exception handling.

The code is commented.

Try to accustom yourself with the sprintf function. With it you can build very complex sql statements in an elegant manner.

Good luck!

<?php

/*
 * ============================================================
 * Set error reporting level and display errors on screen.
 * Use it ONLY ON A DEVELOPMENT SYSTEM, NEVER ON PRODUCTION!
 * If you activate it on a live system, then the users will see
 * all the errors of your system. And you don't want this!
 * ============================================================
 */
error_reporting(E_ALL);
ini_set('display_errors', 1);

/*
 * User variables.
 */

// "table name" not "title" ;-)
$tableName = 'your_table';

// "Themes" not "theme" ;-)
$themes = array('t1', 't2', 't3', 't4', 't5');

// "Contents" not "content" ;-)
$contents = array('c1', 'c2', 'c3', 'c4', 'c5');

// Counter for building the sql statement's assignment list
// and the input parameters list for the sql statement's markers.
$count = 5;

try {
    /*
     * Create a PDO instance as db connection to a MySQL db.
     */
    $connection = new PDO(
            'mysql:host=localhost;port=3306;dbname=yourDb;charset=utf8'
            , 'yourDbUsername'
            , 'yourDbPassword'
    );

    /*
     * Assign the driver options to the db connection.
     */
    $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
    $connection->setAttribute(PDO::ATTR_PERSISTENT, TRUE);

    /*
     * Build the sql statement and fill the input parameters list.
     * 
     * ------------------------------------------------------------------------
     * Notes:
     * 
     *  - Quote: "You cannot use a named parameter marker of the same name more 
     *    than once in a prepared statement, unless emulation mode is on."
     *    See: http://php.net/manual/de/pdo.prepare.php
     * 
     *  - DON'T use semicolon at the end of sql statements in PHP!
     * ------------------------------------------------------------------------
     */
    // Sql statement's assignment list. Array of "column-name = :column-marker, ..." assignments.
    $assignments = array();

    // Input parameters list, e.g the values for the sql statement markers.
    $bindings = array();

    // Note: Use one iteration variable for both operations!
    for ($i = 1; $i <= $count; $i++) {
        // Add sql assignments to assignment list.
        $assignments[] = sprintf('theme%s = :theme%s, content%s = :content%s', $i, $i, $i, $i);

        // Add corresponding input parameter values to bindings list.
        $bindings[':theme' . $i] = $themes[$i - 1];
        $bindings[':content' . $i] = $contents[$i - 1];
    }

    // Final sql statement.
    $sql = sprintf(
            'UPDATE %s 
            SET header = %s
            %s'
            , $tableName
            , $header
            , $assignments ? ',' . implode(',', $assignments) : ''
    );

    /*
     * Prepare and validate the sql statement.
     * 
     * --------------------------------------------------------------------------------
     * If the database server cannot successfully prepare the statement, PDO::prepare() 
     * returns FALSE or emits PDOException (depending on error handling settings).
     * --------------------------------------------------------------------------------
     */
    $statement = $connection->prepare($sql);

    if (!$statement) {
        throw new UnexpectedValueException('The sql statement could not be prepared!');
    }

    /*
     * Bind the input parameters to the prepared statement.
     * 
     * -----------------------------------------------------------------------------------
     * Unlike PDOStatement::bindValue(), when using PDOStatement::bindParam() the variable 
     * is bound as a reference and will only be evaluated at the time that 
     * PDOStatement::execute() is called.
     * -----------------------------------------------------------------------------------
     */
    foreach ($bindings as $key => $value) {
        // Get the name of the input parameter by its key in the bindings array.
        $inputParameterName = is_int($key) ? ($key + 1) : (':' . ltrim($key, ':'));

        // Get the PDO::PARAM_* constant, e.g the data type of the input parameter, by its value.
        $inputParameterDataType = PDO::PARAM_STR;
        if (is_int($value)) {
            $inputParameterDataType = PDO::PARAM_INT;
        } elseif (is_bool($value)) {
            $inputParameterDataType = PDO::PARAM_BOOL;
        }

        // Bind the input parameter.
        $bound = $statement->bindValue($inputParameterName, $value, $inputParameterDataType);

        if (!$bound) {
            throw new UnexpectedValueException('An input parameter can not be bound!');
        }
    }

    /*
     * Execute the prepared statement.
     * 
     * ------------------------------------------------------------------
     * PDOStatement::execute returns TRUE on success or FALSE on failure.
     * ------------------------------------------------------------------
     */
    $executed = $statement->execute();

    if (!$executed) {
        throw new UnexpectedValueException('The prepared statement can not be executed!');
    }

    /*
     * Get number of affected rows.
     */
    $numberOfAffectedRows = $statement->rowCount();

    /*
     * Display results.
     */
    echo $numberOfAffectedRows;

    /*
     * Close connection.
     */
    $connection = NULL;
} catch (PDOException $exc) {
    echo $exc->getMessage();
    // Log the whole exception object to a file.
    // $logger->log($exc);
    exit();
} catch (Exception $exc) {
    echo $exc->getMessage();
    // Log the whole exception object to a file.
    // $logger->log($exc);
    exit();
}

If you wish, see my answer here (the "EDIT" part), where I posted a db adapter class. It takes care of all the db operations, validations and exception handling cases for you.