Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to Generate an SQL Update Statement From an Array

So basically I have a Database class in which you can do the basic operations (Create, Read, Update and Delete) and this is what I came up with for the update method:

public function updateById($table, $id, $updates = []): void
{
        // Generate the SQL statement based on the updates array
        // e.g: updateById('test', 1, [
        //     'column1' => 'newValue1',
        //     'column2' => 'newValue2'
        // ]);

        $st = "UPDATE $table SET ";
        $keys = array_keys($updates);
        $values = array_values($updates);

        for ($i = 0; $i < count($keys); $i++) {
            if ($i != count($keys) - 1) {
                $st .= $keys[$i] . "='" . $values[$i] . "', ";
            } else {
                $st .= $keys[$i] . "='" . $values[$i] . "' ";
            }
        }

        $st .= "WHERE id=$id";

        $query = $this->connection()->prepare($st);
        $query->execute();
}

It does the trick but it looks messy and inefficient. Is there any way I can improve this piece of code?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

NOTE

As YourCommonSense pointed out in the comments, this answer is NOT completely SQL injection safe. https://phpdelusions.net/pdo/sql_injection_example

The Answer

I think it’s easier to work with arrays than strings.

This code should do what you want, in a more secure way.

public function updateById($table, $id, $updates = array())
    {
        
        //loop over update fields to generate the SET clause
        $return_arr = [];
        foreach(array_keys($updates) as $key) {
            $return_arr[] = "`{$key}`=:{$key}";
        }
        $set_clause = implode(', ', $return_arr);
        
        //add the id to the query. NOTE: MUST BE DONE AFTER THE ABOVE LOOP
        $updates['id'] = $id;
        
        //prepare the query
        $query = $this->connection()->prepare("UPDATE {$table} SET {$set_clause} WHERE id=:id");
        
        //execute the query, pass named parameters to execute.
        $query->execute($updates);
    }

Also, I would pass a key->value pair for $id as well, so you can update by any or multiple different columns as well.

updateTable($table, $update_ids, $updates = array())
    {
        
        //in this version, we will use anonymous parameters, because the WHERE clause may share the same keys as the SET clause
        //which could sometimes cause unintended actions
        $params = [];
        
        
        //loop over update fields to generate the SET clause
        $set_clause_parts = [];
        foreach($updates as $key => $value) {
            $set_clause_parts[] = "`{$key}`=?";
            $params[] = $value;
        }
        $set_clause = implode(', ', $set_clause_parts);
        
        //add the ids to the query. NOTE: MUST BE DONE AFTER THE ABOVE LOOP
        $where_clause_parts = [];
        foreach($update_ids as $key => $value) {
            $where_clause_parts[] = "`{$key}`=?";
            $params[] = $value;
        }
        $where_clause = implode(', ', $where_clause_parts);
        
        //prepare the query
        $query = $this->connection()->prepare("UPDATE {$table} SET {$set_clause} WHERE {$where_clause}");
        
        //execute the query, pass named parameters to execute.
        $query->execute($params);
    }

NOTE

The $table variable is NOT sql injection proof. This is probably okay if the value does not come from user submitted data. If it IS somehow from user submitted data, such as an HTML form, you should probably verify that it is a valid table in your database. I usually do this by running a query that returns all the table names in my database and checking against it.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading