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();
Related
I am trying to insert multiple rows into a table based on the array...with each $value being each of the comma separated values.
I know this is NOT the best way or even correct way to do this - just trying to get some guidance on how to achieve this the right way.
$someArray=array(96,97,98,99,100,101,103,105);
foreach($someArray as $value){
$sql = "INSERT INTO bid_package(user_company) VALUES('".$value."');";
echo $sql;
echo "<br />";
INSERT INTO bid_package(user_company) VALUES('96');
INSERT INTO bid_package(user_company) VALUES('97');
INSERT INTO bid_package(user_company) VALUES('98');
INSERT INTO bid_package(user_company) VALUES('99');
INSERT INTO bid_package(user_company) VALUES('100');
INSERT INTO bid_package(user_company) VALUES('101');
INSERT INTO bid_package(user_company) VALUES('103');
INSERT INTO bid_package(user_company) VALUES('105');
You can put multiple lists of values in a single INSERT:
$values = implode(', ', array_map(function($val) {
return "($val)";
}, $someArray));
$sql = "INSERT INTO bid_package (user_company) VALUES $values;";
This will create a query that looks like this:
INSERT INTO bid_package (user_company) VALUES (96), (97), (98), (99), (100), (101), (103), (105);
If you were using PDO, it would be better to use a prepared statement, to prevent SQL-injection.
$values = implode(', ', array_fill(0, count($someArray), "(?)"))
$sql = "INSERT INTO bid_package (user_company) VALUES $values;"
$stmt = $conn->prepare($sql);
$stmt->execute($someArray);
First, you should be using prepared statements instead of inserting the variable directly into the query. Here is one way of doing what you are attempting.
$mysqli = new mysqli('localhost', 'user', 'password', 'mysampledb'); // your mysqli handle
$stmt = $mysqli->prepare("INSERT INTO SampleTable VALUES (?)"); // prepare your query
//bind value as a reference
$stmt->bind_param('s', $val);
//define values
$someArray=array(96,97,98,99,100,101,103,105);
//loop through values
foreach($someArray as $val) {
//execute statement
$stmt->execute();
}
If you are ever passing data to a query, you should use prepared statements.
I need to insert many rows ( between 150 to 300 ) into MySQL table and I want to know the better of the following approaches in terms of performance:
Approach 1 :
foreach( $persons as $person ){
$stmt = $dbLink->prepare( "INSERT INTO table SET id = :ID,
name = :name,
email = :email,
mobile = :mobile");
$stmt->execute( array( ':ID'=>$person->getID(),
':name'=>$person->getName(),
':email'=>$person->getEmail(),
':mobile'=>$person->getMobile(),
) );
}
Approach 2:
$stmt = $dbLink->prepare( "INSERT INTO table SET id = :ID,
name = :name,
email = :email,
mobile = :mobile");
$stmt->bindParam( ':ID', $person->getID(), PDO::PARAM_STR );
$stmt->bindParam( ':name', $person->getName(), PDO::PARAM_STR );
$stmt->bindParam( ':email', $person->getEmail(), PDO::PARAM_STR );
$stmt->bindParam( ':mobile', $person->getMobile(), PDO::PARAM_STR );
foreach( $persons as $person ){
$stmt->execute();
}
It is the amount of calls to the database what makes the difference. Reduce the amount of calls as much as possible.
Instead of this:
insert (a,b,c) values (d,e,f);
insert (a,b,c) values (g,h,i);
insert (a,b,c) values (j,k,l);
insert (a,b,c) values (m,n,o);
do this:
insert (a,b,c) values (d,e,f),(g,h,i),(j,k,l),(m,n,o);
Thus making in one call what you would do in 4 calls.
You can use the below code to avoid multiple SQL calls and insert the data in Single SQL call
$first_string = "INSERT INTO table (id, name, email,mobile) VALUES ";//Basic query
foreach( $persons as $person )
{
$first_string .="(".$person->getID().",".$person->getName().",".$person->getEmail().",".$person->getMobile()."),";//Prepare the values
}
$final_query_string = substr($first_string, 0,-1);// This will remove the extra , at the end of the string
$stmt = $dbLink->prepare($final_query_string);
$stmt->execute();
Now execute the final query string prepared.
This way the query is prepared as the string and you need to execute it in one go.
This will make a single SQL call
To answer to your question, this is the way you should structure your prepare / bind / execute phases:
//prepare the query only the first time
$stmt = $dbLink->prepare( "INSERT table (id, name, email, mobile)
VALUES (:ID, :name, :email, :mobile)" );
//bind params and execute for every person
foreach( $persons as $person ){
$stmt->bindValue( ':ID', $person->getID(), PDO::PARAM_STR );
$stmt->bindValue( ':name', $person->getName(), PDO::PARAM_STR );
$stmt->bindValue( ':email', $person->getEmail(), PDO::PARAM_STR );
$stmt->bindValue( ':mobile', $person->getMobile(), PDO::PARAM_STR );
$stmt->execute();
}
If you have PDO::ATTR_EMULATE_PREPARES = false, the query will be prepared by mysql only the first time.
In the first case it would be re-prepared for every loop cycle
As correctly other users are saying, remember that a better performance improvement would be to make ONLY one insert instead of many insert in a for loop
EDIT: How to use parameter bindings AND one query
To use parameters' binding and only one query a solution could be:
$placeholders = ""; //this will be filled with placeholders : ( :id_1, :name_1, :email_1, :mobile_1),( :id_2 ... )
$parameters = array(); //this will keep the parameters bindings
$i = 1;
foreach( $persons as $person )
{
//add comma if not first iteration
if ( $placeholders )
$placeholders .= ", ";
//build the placeholders string for this person
$placeholders .= "( :id_$i, :name_$i, :email_$i, :mobile_$i )";
//add parameters for this person
$parameters[":id_$i"] = $person->getID();
$parameters[":name_$i"] = $person->getName();
$parameters[":email_$i"] = $person->getEmail();
$parameters[":mobile_$i"] = $person->getMobile();
$i++;
}
//build the query
$stmt = $dbLink->prepare( "INSERT INTO table (id, name, email, mobile)
VALUES " . $placeholders );
//execute the query passing parameters
$stmt->execute( $parameters );
In the first part of the loop we build the string $placeholders with a set of placeholders for every person, in the second part of the loop we store the bindings of the values of the placeholders in the $parameters array
At the end of the loop we should have all the placeholders and parameters set, and we can execute the query passing the $parameters array to the execute method. This is an alternative way in respect to use the bindValue / bindParam methods but the result should be the same
I think this is the only way to use parameter bindings AND use only one query
//declare array of values to be passed into PDO::Statemenet::execute()
$values = array();
//prepare sql string
$sql = 'INSERT INTO students ( id, name, email, mobile ) VALUES ';
foreach( $students as $student ){
$sql .= '( ?, ?, ?, ? ),'; //concatenate placeholders with sql string
//generate array of values and merge with previous values
$values = array_merge( $values, array( $student->getID(),
$student->getName(),
$student->getEmail(),
$student->getMobile(),
)
);
}
$sql = rtrim( $sql, ',' ); //remove the trailing comma (,) and replace the sql string
$stmt = $this->dbLink->prepare( $sql );
$stmt->execute( $values );
Full credits to all who have inspired me to arrive at this solution. This seems to be terse and clear:
In particular, the answer of JM4 at PDO Prepared Inserts multiple rows in single query really helped. I also recognise Moppo on this page.
I have to insert single set of data multiple times , say n rows.
INSERT INTO MyTable VALUES ("John", 123, "US");
Can I insert all n rows in a single SQL statement?
here n is dynamic value n is user input , how to make insert query n times , any idea.
$sql = "INSERT INTO `mytable` VALUES(`field1`,`field2`,`field3`) VALUES ";
$count = 5;
for($i=0;$i<$coutn;$i++)
{
$sql .= " ('john','123','us' )";
}
is this correct way..
Yep, this can be done easily, it should look something like this:
INSERT INTO MyTable VALUES ("John", 123, "US"), ("Carl", 123, "EU"), ("Jim", 123, "FR");
However, it is good programming practice to specify the columns of your table in the query, for example:
INSERT INTO MyTable (Column1, Column2, Column3)
VALUES ("John", 123, "US"), ("Carl", 123, "EU"), ("Jim", 123, "FR");
EDIT : You can build your query like this (in for cycle), the $total is your user input:
$sql = "INSERT INTO MyTable (Column1, Column2, Column3) VALUES";
//Build SQL INSERT query
for ($i = 1; $i <= $total; $i++) {
$sql .= " ($value1, $value2, $value3), ";
}
//Trim the last comma (,)
$sql = rtrim($sql,",");
//Now, the $sql var contains the complex query.
$result = mysql_query($sql);
As you can see we do not execute the INSERT statement in the loop, but rather we build the SQL query text and then we will execute it in one pass.
I've got a portion of code that is supposed to take the data entered in a form, store it in an array and then enter it into the database. I have used var_dump on $fields and $data and they are both returning the information entered in the field (in the add_habbo function). So the problem I've got is that the MYSQL/PDO code isn't inserting this data into the database.
This is the code that I am using to insert them into the database:
$fields = '`' . implode('`, `', array_keys($habbo_data)) . '`';
$data = '\'' . implode('\', \'', $habbo_data) . '\'';
var_dump($fields);
var_dump($data);
global $con;
$query = "INSERT INTO `personnel` (:fields) VALUES (:data)";
$result = $con->prepare($query);
$result->bindParam(':fields', $fields, PDO::PARAM_STR);
$result->bindParam(':data', $data, PDO::PARAM_STR);
$result->execute();
I get the impression it has something to with the bindParam sections, possibly PDO::PARAM_STR? Thanks for your assistance!
Update:
$fields = '`' . implode('`, `', array_keys($habbo_data)) . '`';
$fields_data = ':' . implode(', :', array_keys($habbo_data));
var_dump($fields);
var_dump($fields_data);
global $con;
$query = "INSERT INTO `personnel` (`rank`, `habbo_name`, `rating`, `asts`, `promotion_date`, `transfer_rank_received`, `cnl_trainings`, `rdc_grade`,
`medals`, `branch`) VALUES ({$fields_data})";
$result = $con->prepare($query);
$result->execute($habbo_data);
$arr = $result->errorInfo();
print_r($arr);
Error:
Array ( [0] => 21S01 [1] => 1136 [2] => Column count doesn't match
value count at row 1 )
Prepared statements are not the same as copy and paste!
INSERT INTO `personnel` (:fields) VALUES (:data)
You're telling PDO/MySQL here that you want to insert exactly one piece of data (:data) into one field (:field). The value is one string containing commas, not several values separated by commas.
Furthermore you can only bind data, not structural information like field names. You will have to create a query like so:
INSERT INTO `personnel` (foo, bar, baz) VALUES (?, ?, ?)
and then bind data to the three placeholders separately.
You cannot do that:
You need to add each variable / field-name and value individually;
You can only bind values and not table- or field-names.
Table- and field-names you will have to inject directly into your sql so to prevent sql injection problems, you need to check them against a white-list before doing that.
So in your case that would be something like (rough draft):
// assuming all fields have been checked against a whitelist
// also assuming that the array keys of `$habbo_data` do not contain funny stuff like spaces, etc.
$fields = '`' . implode('`, `', array_keys($habbo_data)) . '`';
$fields_data = ':' . implode(', :', array_keys($habbo_data));
var_dump($fields);
var_dump($fields_data);
global $con;
$query = "INSERT INTO `personnel` ({$fields}) VALUES ({$fields_data})";
$result = $con->prepare($query);
$result->execute($habbo_data);
Note that I am not manually binding the variables any more but sending the associative $habbo_data array directly as a parameter to the execute method, see example #2.
I'm creating an insert statement like the following
$stmt = $connection->prepare("INSERT INTO table (first, second, ...) VALUES (?, ?, ...)");
$stmt->bind_param("ss...", $first, $second, ...);
How can I get the filled out query? E.g.
INSERT INTO table (first, second, ...) VALUES ('one','two', ....)
unfortunately you don't.
As I understand it these are assigned lazily and readied for the next execution of the query.
If you need to test in our db client then vardump the quer and the parameters.
$qry = "INSERT INTO table (first, second, ...) VALUES (?, ?, ...)";
$stmt = $connection->prepare( $qry );
$stmt->bind_param("ss...", $first, $second, ...);
var_dump( $qry , "ss...", $first, $second, ... );
Can I sugeest you look at using PDO and consider using bindValue over bindParam if you don't need to execute the query repeatedly.