How storing array values in different columns of table using php - php

Here is the piece of code so far I've tried:
$month = array('red','green','red');
$values = array();
foreach($month as $dataset)
{
$values[] = ($dataset);
}
$columns = implode(", ",array_keys($values));
$escaped_values = array_values($values);
$valu = implode(", ", $escaped_values);
$sql = "INSERT INTO abc (col1,col2,col3) VALUES ('$valu');";
Here is the output:
Error: INSERT INTO abc (col1,col2,col3) VALUES ('red, green, red');
Column count doesn't match value count at row 1
What I am trying to do is to store values in the array where the value of the array may vary depending upon the value the user gave, and then store it in different columns. For example, if the total columns are 3 and array value is 2 then store values in col1 and col2 and null value in col3.

With the single quotes around the whole string 'red, green, red' that is the value for col1 only.
It should look more like this 'red','green','red'.
So quick fix is this $valu = implode("','", $escaped_values);
Added a single quotes inside your implode.
The outside quotes will be captured in the final statement as detailied in the problem above:
$sql = "INSERT INTO abc (col1,col2,col3) VALUES ('$valu');";

Here the Code after making it work properly
$month = array('red','green','red');
$values = array();
foreach($month as $dataset)
{
$values[] = "'{$dataset}'";
}
$columns = implode(", ",array_keys($values));
$escaped_values = array_values($values);
$valu = implode(", ", $escaped_values);
$sql = "INSERT INTO abc (col1,col2,col3) VALUES ($valu);";

The values are into the single quote. Please check below example.
INSERT INTO abc (col1,col2,col3) VALUES ('red', 'green', 'red');

No one else seems to have addressed the actual issue.
What I am trying to do is to store values in the array where the value
of the array may vary depending upon the value the user gave, and then
store it in different columns. For example, if the total columns are 3
and array value is 2 then store values in col1 and col2 and null value
in col3.
So if the values come in as an array at different lengths, and you want to insert as null or limit to the max length of the columns then you can do it like the following.
Ideally, you want to produce an array which looks like:
$data = [
'col1' => 'red',
'col2' => 'green',
'col3' => null
];
To do that without any looping define the database columns, then create an array of the same length of null values, then slice the input array to the same length and merge, this will produce an array like above.
<?php
$columns = [
'col1',
'col2',
'col3',
];
$month = [
'red',
'green'
];
$data = array_combine(
$columns,
array_slice($month, 0, count($columns))+array_fill(0, count($columns), null)
);
Now you simply need to implode the array into your query, using ? for placeholders for the prepared query.
$sql = '
INSERT INTO abc (
'.implode(', ', array_keys($data)).'
) VALUES (
'.implode(', ', array_fill(0, count($data), '?')).'
)';
Will produce:
INSERT INTO abc (
col1, col2, col3
) VALUES (
?, ?, ?
)
Then just do your query, for example:
$stmt = $pdo->prepare($sql);
$stmt->execute($data);
Simple clean and safe.

Related

pdo array getting Array to string conversion error

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);

insert values from an object where keys are columnn names

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.

How to insert values to table that are there only in the JSON object in PHP

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 multiple rows in database using pdo's

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();

Insert multiple rows with PDO prepared statements

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);

Categories