When I run this code it should store ben in the database but, it says Array in the first_name column and it gives the string to conversion error. How would I get rid of the error?
<?php $data = ['first_name' => 'ben'] ?>
<?php $sql = "INSERT INTO names (first_name) values (?);" ?>
<?php $statement = $pdo->prepare($sql); ?>
<?php $statement->execute([$data]); ?>
PDO has two different ways to bind parameters. The first is positional. In this case, the array you pass to execute() should be an indexed array, with values in the same order that you want them to bind to the question marks:
$sql = "INSERT INTO table (col1, col2) values (?, ?)";
$data = ['value for col1', 'value for col2'];
Note the values must be in the same order that they're going to be used:
$data = ['value for col2', 'value for col1']; // This won't work, wrong order!
The alternative (and in my opinion, superior) method is to use named parameters. Here, you need to use an associative array with a key named the same as your parameter placeholder.
$sql = "INSERT INTO table (col1, col2) values (:col1, :col2)";
$data = ['col1' => 'value for col1', 'col2' => 'value for col2'];
The order of these now does not matter because they're keyed by the array name instead of the position:
$data = ['col2' => 'value for col2', 'col1' => 'value for col1']; // Still good!
Your problem (in addition to the extra array wrap that #Sammitch pointed out) is that you have mixed these two techniques together in an incompatible way -- you're using positional parameters, but have provided an associative array. So, in your case, you either need to use positional parameters and an indexed array:
$data = ['ben'];
$sql = "INSERT INTO names (first_name) values (?);";
$statement = $pdo->prepare($sql);
$statement->execute($data);
Or named parameters and an associative array:
$data = ['first_name' => 'ben'];
$sql = "INSERT INTO names (first_name) values (:first_name);";
$statement = $pdo->prepare($sql);
$statement->execute($data);
I have a json_encoded string where keys are column names and need to insert corresponding values
$str = {"fname":"lorem","sname":"ipsum","nick":"dolor"};
fname sname nick - are column names - and need to insert lorem ipsum dolor
I made an object - $obj = json_decode($str); - but what then?
in a plain example - without the object - it would be like this:
function insert($fname, $sname, $nick){
$sq = "insert into table (fname, sname, nick) values (:afname, :asname, :anick)";
$st = $db->prepare($sq);
$st->execute([
":afname" => $fname, // lorem
":asname" => $sname, // ipsum
":anick" => $nick // dolor
]);
}
how to do this using the given object?
After making object, just pass these in insert method(use your above mentioned insert method)
$obj = json_decode($str);
insert($obj->fname, $obj->sname, $obj->nick);
If you wanna pass as an object in the function, you can do in following manner.
function insert($obj){
$sq = "insert into table (fname, sname, nick) values (:afname, :asname, :anick)";
$st = $db->prepare($sq);
$st->execute([
":afname" => $obj->fname, // lorem
":asname" => $obj->sname, // ipsum
":anick" => $obj->nick // dolor
]);
}
If you want to use dynamically insert columns with their values. You can do so in following manner.
$arr = json_decode($str, true);
$sq = "insert into table (". implode(', ', array_keys($arr)) . ") values (" . implode(',',array_fill(0, count($arr),"?")) . ")";
$st = $db->prepare($sq);
$st->execute(array_values($arr));
Here
implode(', ', array_keys($arr)) - create a comma separated column names based on array keys.
implode(',',array_fill(0, count($arr),"?")) - create ? for prepared statement. Number of ? would be equal to array length and then concatenated with ,.
array_values($arr) pass values as array.
I've a table which is created with below SQL statement
CREATE TABLE example (
col1 varchar(20) DEFAULT NULL,
col2 varchar(20) DEFAULT NULL,
col3 varchar(20) DEFAULT NULL
)
I want to insert values to this table from a JSON object. JSON object is constructed such way that its key is the column name and value is the value to be inserted.
How do I write a PHP code to only insert the values that are there in the JSON object?
For instance, If I have a JSON object
{
"col1": "some value",
"col3": "some value"
}
The insert statement should only insert values to col1 and col3 and the col2 should remain as NULL.
Please help me out to solve this puzzle. PHP with PDO is preferable.
Experiments performed so far
$object = json_decode($jsonObject);
foreach ($object as $col => $val) {
$columns .= $col . ",";
$values .= $val . ",";
}
$sql = "INSERT INTO example (" .substr($columns, 0, strlen($columns)-2) .
") VALUES (" . substr($values, 0, strlen($columns)-2) . ")";
Your code is pretty close. The problem is that you don't have quotes around each value in $values.
Here's another way to write it:
$object = json_decode($jsonObject, true);
$columns = implode(', ', array_keys($object);
$values = implode(', ', array_map(function($x) { return "'$x'"; }, $object));
$sql = "INSERT INTO example($columns) VALUES ($values)";
The function in array_map() returns each value with quotes around it, then implode() combines them all with commas.
If you're using PDO, you can pass an array of values to PDOStatement::execute().
$values = array_values($object);
// Create "?, ?, ?, ..." string with enough placeholders for the values
$placeholders = implode(', ', array_fill(0, count($values), '?'));
$sql = "INSERT INTO example($columns) VALUES ($placeholders)";
$stmt = $pdo->prepare($sql);
$result = $stmt->execute($values);
insert into test (sometext) values ("?"),("?")
$a= array("weird' text","sdfa");
I want to insert text into the table test in column sometext using bind parameter and I do not want the execute statement in a loop. I cannot implode the array in ("?"),("?") form as the query might crash coz the text can be composed of quotes.
So is there a way to achieve this using PDO in one(1) execute statement?
I cannot implode the array in ("?"),("?") form as the query might crash coz the text can be composed of quotes.
The prepared statements are there to solve quoting/escaping problems.
This syntax is wrong1:
insert into test (sometext) values ("?"),("?")
You don't have to wrap parameters by quotes, you have to write query in this form:
INSERT INTO test (sometext) VALUES (?),(?)
Then, you can use implode() without worrying about quotes:
$a = array( "weird' text", "sdfa" );
$query = "INSERT INTO test (sometext) VALUES (" . implode( "),(", array_fill( 0, count( $a ), "?" ) ) . ")";
$stmt = $db->prepare( $query );
$stmt->execute( $a );
As alternative, you can use substr and str_repeat instead of implode:
$query = "INSERT INTO test (sometext) VALUES " . substr( str_repeat( "(?),", count( $a ) ), 0, -1 );
1 Using insert into test (sometext) values ("?"),("?") you insert in your fields literally two question marks.
$stmt = $conn->prepare("INSERT INTO test (field1, field2, field3) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $field1, $field2, $field3);
// set parameters and execute
$field1 = "test";
$field2 = "test2";
$field3 = "test#test.cc";
$stmt->execute();
I would like to know if it is possible to insert multiple rows using one prepared statement.
Below is an example of how I would normally insert one row into the db:
$params=array();
$params[':val1']="val1";
$params[':val2']="val2";
$params[':val3']="val3";
$sql="INSERT INTO table VALUES (col1,col2,col3) VALUES (:val1,:val2,:val3)";
$stmt=DB::getInstance()->prepare($sql);
$stmt->execute($params);
The values I want to insert will come from an array, for example:
$values[0]['val1'];
$values[0]['val2'];
$values[0]['val3'];
$values[1]['val1'];
$values[2]['val2'];
etc.
This code may have to insert a few hundred rows at once, I thought about creating a loop to create hundreds of params and then append the sql statement with an extra insert for each row but I thought there must be a better way. What would be the best way to do this?
The first important thing to say is that you can insert multiple rows thanks to only one INSERT query
INSERT INTO Table (col1, col2, col3)
VALUES ('abc', 'def', 'ghi'),
('abc', 'def', 'ghi'),
('abc', 'def', 'ghi'),
('abc', 'def', 'ghi'),
('abc', 'def', 'ghi')
-- and so on...
Once you know that, you're able to get a good solution with PDO (for instance).
You have to keep in mind that you want a complete prepare and execute process (in term of security, you have to pass each parameter separately).
Let's say you have rows to insert structured as follow:
$rows = array(
array('abc', 'def', 'ghi'), // row 1 to insert
array('abc', 'def', 'ghi'), // row 2 to insert
array('abc', 'def', 'ghi') // row 3 to insert
// and so on ...
);
Your goal is to have this result as a prepared query:
INSERT INTO Table (col1, col2, col3)
VALUES (?, ?, ?),
(?, ?, ?),
(?, ?, ?)
With its corresponding execute:
PDOStatement::execute(array('abc', 'def', 'ghi', 'abc', 'def', 'ghi', 'abc', 'def', 'ghi'));
Well, you only have to do it now:
$rows = array(
array('abc', 'def', 'ghi'),
array('abc', 'def', 'ghi'),
array('abc', 'def', 'ghi')
);
$row_length = count($rows[0]);
$nb_rows = count($rows);
$length = $nb_rows * $row_length;
/* Fill in chunks with '?' and separate them by group of $row_length */
$args = implode(',', array_map(
function($el) { return '('.implode(',', $el).')'; },
array_chunk(array_fill(0, $length, '?'), $row_length)
));
$params = array();
foreach($rows as $row)
{
foreach($row as $value)
{
$params[] = $value;
}
}
$query = "INSERT INTO Table (col1, col2, col3) VALUES ".$args;
$stmt = DB::getInstance()->prepare($query);
$stmt->execute($params);
And... That's it!
This way, each param is treated separately, which is what you want (security, security, security!) and all of it, in a dynamic way, with only one INSERT query
If you have too many rows to insert (see this), you should execute one by one
$rows = array(
array('abc', 'def', 'ghi'), // row 1 to insert
array('abc', 'def', 'ghi'), // row 2 to insert
array('abc', 'def', 'ghi') // row 3 to insert
// and so on ...
);
$args = array_fill(0, count($rows[0]), '?');
$query = "INSERT INTO Table (col1, col2, col3) VALUES (".implode(',', $args).")";
$stmt = $pdo->prepare($query);
foreach ($rows as $row)
{
$stmt->execute($row);
}
If your table is transactional (for example an InnoDB), you can use a Transaction to speed up your insertions. A transaction has also the advantage of roll backs.
$pdo = DB::getInstance();
$stmt = $pdo->prepare('INSERT INTO table VALUES (col1, col2, col3) VALUES (:val1, :val2, :val3)');
$pdo->beginTransaction();
// The queries are not executed yet, but pushed to a transaction "stack"
foreach ($values as $value) {
$stmt->execute([
':val1' => $value['val1'],
':val2' => $value['val2'],
':val3' => $value['val3'],
]);
}
// Executes all the queries "at once"
$pdo->commit();
If you're only inserting a few hundred rows, I'd favor simpler code like the following. Prepare a single-row INSERT statement, and then loop over your data array, executing the prepared query once for each row.
$rows = array(
array('abc', 'def', 'ghi'), // row 1 to insert
array('abc', 'def', 'ghi'), // row 2 to insert
array('abc', 'def', 'ghi') // row 3 to insert
// and so on ...
);
$params = implode(",", array_fill(0, count($rows[0]), "?"));
$sql = "INSERT INTO mytable VALUES ($params)";
$stmt = $pdo->prepare($sql); // rely on exceptions for error detection
foreach ($rows as $row) {
$stmt->execute($row);
}
MySQL does support multi-row INSERT syntax of course, so you could try putting that together.
$params = implode(",", array_fill(0, count($rows[0]), "?"));
$tuples = "(" . implode("),(", array_fill(0, count($rows), $params)) . ")";
$sql = "INSERT INTO mytable VALUES $tuples";
$values = call_user_func_array("array_merge", $rows);
$stmt = $pdo->prepare($sql);
$stmt->execute($values);
But if you try to create a single INSERT statement with as many tuples as the items in your data array, you might accidentally generate an SQL statement that is longer than the maximum packet length.
If you have thousands of rows, enough so that executing a prepared statement one row at a time is too much overhead, you should use LOAD DATA INFILE.
To keep your code, you have to make a loop for executing all insertions you need :
$array_params = array();
$params[':val1']="val1 1";
$params[':val2']="val1 2";
$params[':val3']="val1 3";
$array_params[] = $params;
$params[':val1']="val2 1";
$params[':val2']="val2 2";
$params[':val3']="val2 3";
$array_params[] = $params;
$sql="INSERT INTO table (col1,col2,col3) VALUES (:val1,:val2,:val3)";
$stmt=DB::getInstance()->prepare($sql);
foreach($array_params as $params)
{
$stmt->execute($params);
}
But its possible to execute multiple insertions with one query like INSERT INTO table (col1,col2,col3) VALUES ("val1","val2","val3"),("val4","val5","val6"),("val7","val8,"val9"), by using something like this to build the query:
$all_inserts = array( array('val1', 'val2', 'val3'),array('val4', 'val5', 'val6'));
$sql = 'INSERT INTO table (col1,col2,col3) VALUES ';
$rows = array();
foreach ($all_inserts as $one_insert)
{
$rows[] = '('.implode(',', $pdo->quote($one_insert).')';
}
$sql .= ' '.implode(',', $rows);
$pdo->query($sql);