I ran into the following question while writing a PHP script. I need to store the first two integers from an array of variable lenght into a database table, remove them and repeat this until the array is empty. I could do it with a while loop, but I read that you should avoid writing SQL statements inside a loop because of the performance hit.
A simpliefied example:
while(count($array) > 0){
if ($sql = $db_connect->prepare("INSERT INTO table (number1, number2) VALUES (?,?)")){
$sql->bind_param('ii',$array[0],$array[1]);
$sql->execute();
$sql->close();
}
array_shift($array);
array_shift($array);
}
Is this the best way, and if not, what's a better approach?
You can do something like this, which is way faster aswell:
Psuedo code:
$stack = array();
while(count($array) > 0){
array_push($stack, "(" . $array[0] . ", " . $array[1] . ")");
array_shift($array);
array_shift($array);
}
if ($sql = $db_connect->prepare("INSERT INTO table (number1, number2)
VALUES " . implode(',', $stack))){
$sql->execute();
$sql->close();
}
The only issue here is that it's not a "MySQL Safe" insert, you will need to fix that!
This will generate and Array that holds the values. Within 1 query it will insert all values at once, where you need less MySQL time.
Whether you run them one by one or in an array, an INSERT statement is not going to make a noticeable performance hit, from my experience.
The database connection is only opened once, so it is not a huge issue. I guess if you are doing some insane amount of queries, it could be.
I think as long as your loop condition is safe ( will break in time ) and you got something from it .. it's ok
You would be better off writing a bulk insert statement, less hits on mysql
$sql = "INSERT INTO table(number1, number2) VALUES";
$params = array();
foreach( $array as $item ) {
$sql .= "(?,?),\n";
$params[] = $item;
}
$sql = rtrim( $sql, ",\n" ) . ';';
$sql = $db_connect->prepare( $sql );
foreach( $params as $param ) {
$sql->bind_param( 'ii', $param[ 0 ], $param[ 1 ] );
}
$sql->execute();
$sql->close();
In ColdFusion you can put your loop inside the query instead of the other way around. I'm not a php programmer but my general belief is that most things that can be done in language a can also be done in language b. This code shows the concept. You should be able to figure out a php version.
<cfquery>
insert into mytable
(field1, field2)
select null, null
from SomeSmallTable
where 1=2
<cfloop from="1' to="#arrayLen(myArray)#" index="i">
select <cfqueryparam value="myArray[i][1]
, <cfqueryparam value="myArray[i][]
from SomeSmallTable
</cfloop>
</cfquery>
When I've looked at this approach myself, I've found it to be faster than query inside loop with oracle and sql server. I found it to be slower with redbrick.
There is a limitation with this approach. Sql server has a maximum number of parameters it will accept and a maximum query length. Other db engines might as well, I've just not discovered them yet.
Related
I am not really sure if this is possible, or if there is any alternative way to do this.
The following code takes multiple input from a user and inserts them in different rows, I don't want it like that. I am looking for a way to insert them in the same row.
<?php $test=$_POST['test'];
foreach ($test as $a => $b){?>
<?php echo $test[$a];?>
<?php
if( !$error ) {
$query = "INSERT INTO test_tbl(test) VALUES('$test[$a]')";
$output = mysql_query($query);
if ($output) {
$errTyp = "success";
$errMSG = "Update Posted";
?>
I am aware there is a GROUP_CONCAT function but I can't seem to get it to work in insert statements and from researching I found out it doesn't really work with insert only with select. So is there any way of sorting this mess?
Here is my attempt on the GROUP_CONCAT (Obviously it's a big error that I receive)
$query = "INSERT INTO testing(item) VALUES(GROUP_CONCAT($test[$a]))";
PS I know this is completely against normalization standards but I am doing it since a customer requested it..
If i understood correctly you are inserting in a foreach loop, this will insert each $test[$a] seperately each time the loop runs. ALternatively you can put all $test[$a] values in an array and then insert that array in one row(which is way faster than multiple insert queries).
Here is a way to do it:
$all_test_values = array();
foreach ($test as $a => $b){
$all_test_values[] = $test[$a];
}
$comma_separated = implode(",", $all_test_values);
if( !$error ) {
$query = "INSERT INTO test_tbl(test) VALUES('$comma_separated')";
$output = mysql_query($query);
}
PS: mysql is bad use mysqli instead
I'm hoping someone can give me a suggestion on a challenge I am facing. I am not sure that I'm able to do this the way I envision, so looking for advice from those more experienced.
I have a database table with around 20 columns. It's a lot of columns and unfortunately I cannot change that. The goal is to take a form submission and insert it into this table. So what I have is, the field names are identical to the column names in the database.
To try and keep the code cleaner, I would like to just pull the entire form (key and value) in, instead of doing the traditional $varWhatever = $_POST['whatever']; 20 times. Using something like this: foreach ($_POST as $key => $value)
Now my question is, if at all possible, how can I run that foreach loop in a way that will let me put the keys and values into a single SQL statement?
"INSERT INTO table_name (Loop all keys here) VALUES (Loop related values here)"
Is this even possible, or should I just go back to the more traditional way I mentioned above?
One way I am thinking is, before starting the loop, I could create the empty row and grab it's ID, then within the loop, I could run an update query on the row matching the ID. Sounds sloppy though.
Here is a solution I came up with. You first have to define an array of field names that acts as a whitelist of expected inputs. Then you just loop through that array to build a parameters array to bind the submitted values. And implode the array with a comma when building the query.
$fields = array('field1','field2','field3');
$binds = array();
foreach ($fields as $field) {
$binds[":$field"] = $_POST[$field];
}
$sql = "INSERT INTO table_name (" . implode(',',$fields) . ") VALUES (" . implode(',',array_keys($binds)) . ")";
$db->prepare($sql);
$db->execute($binds);
This assumes you are using PDO.
Yes, you can loop for all keys (eg. do an array_keys), but I don't recommend blindly taking any submission parameter and putting it into a SQL query.
Instead, I would keep a list of all valid columns of the form and work with that, remembering that each value needs sanitization, too.
For example:
<?php
$columns = array('column1', 'column2', 'column3', …);
foreach ($columns as $column) {
if (!isset($_POST[$column])) {
die("No data for column $column\n");
}
}
if (!check_csrf($_POST['csrt_token'])) { … }
# (setup database connection)
$SQL = "INSERT INTO table_name (" . implode(", ", $columns) . ") VALUES (";
foreach ($column as $column) {
$SQL .= "'" . $mysqli->real_escape_string($_POST[$column]) . "',";
}
$SQL[strlen($SQL)-1] = ')';
$mysqli->query($SQL);
I have an array stored in a variable $contactid. I need to run this query to insert a row for each contact_id in the array. What is the best way to do this? Here is the query I need to run...
$contactid=$_POST['contact_id'];
$eventid=$_POST['event_id'];
$groupid=$_POST['group_id'];
mysql_query($query);
$query="INSERT INTO attendance (event_id,contact_id,group_id) VALUES ('$eventid','$contactid','$groupid')";
Use a foreach loop.
$query = "INSERT INTO attendance (event_id,contact_id,group_id) VALUES ";
foreach($contactid as $value)
{
$query .= "('{$eventid}','{$value}','{$groupid}'),";
}
mysql_query(substr($query, 0, -1));
The idea here is to concatenate your query string and only make 1 query to the database, each value-set is separated by a comma
Since no one hasn't stated that yet, you actually cannot do this:
$query = '
INSERT INTO [Table] ([Column List])
VALUES ([Value List 1]);
INSERT INTO [Table] ([Column List])
VALUES ([Value List 2]);
';
mysql_query($query);
as this has been prevented to prevent sql injections in the mysql_query code. You cannot have semicolon within the given query param with mysql_query. With the following exception, taken from the manual comments:
The documentation claims that "multiple queries are not supported".
However, multiple queries seem to be supported. You just have to pass
flag 65536 as mysql_connect's 5 parameter (client_flags). This value
is defined in /usr/include/mysql/mysql_com.h:
#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */
Executed with multiple queries at once, the mysql_query function will
return a result only for the first query. The other queries will be
executed as well, but you won't have a result for them.
That is undocumented and unsupported behaviour, however, and easily opens your code to SQL injections. What you can do with mysql_query, instead, is
$query = '
INSERT INTO [Table] ([Column List])
VALUES ([Value List 1])
, ([Value List 2])
[...]
, ([Value List N])
';
mysql_query($query);
so you can actually insert multiple rows with a one query, and with one insert statement. In this answer there's a code example for it which doesn't concatenate to a string in a loop, which is better than what's suggested in this thread.
However, disregarding all the above, you're probably better of still to use a prepared statement, like
$stmt->prepare("INSERT INTO mytbl (fld1, fld2, fld3, fld4) VALUES(?, ?, ?, ?)");
foreach($myarray as $row)
{
$stmt->bind_param('idsb', $row['fld1'], $row['fld2'], $row['fld3'], $row['fld4']);
$stmt->execute();
}
$stmt->close();
Use something like the following. Please note that you shouldn't be using mysql_* functions anymore, and that your code is suseptible to injection.
for ($i = 0; $i < count($contactid); $i++) {
$query="INSERT INTO attendance (event_id,contact_id,group_id) VALUES ('$eventid','$contactid[$i]','$groupid')";
mysql_query($query);
}
I'm not sure running multiple queries is the best thing to do, so won't recommend making a for loop for example, that runs for each element of the array. I would rather say, make a recursive loop, that adds the new elements to a string, that then gets passed to the query. In case you can give us a short example of your DB structure and how you'd like it to look like (i.e. how the array should go into the table), I could give you an example loop syntax.
Cheers!
What about:
$contactIds = $_POST['contact_id'];
$eventIds = $_POST['event_id'];
$groupIds = $_POST['group_id'];
foreach($contactIds as $key => $value)
{
$currentContactId = $value;
$currentEventId = $eventIds[$key];
$currentGroupId = $groupIds[$key];
$query="INSERT INTO attendance (event_id,contact_id,group_id) VALUES ('$currentEventId','$currentContactId','$currentGroupId')";
mysql_query($query);
}
Well, you could refactor that to insert everything in a single query, but you got the idea.
Hey guys, i'm currently learning php and I need to do this
$connection = mysql_open();
$likes= array();
foreach($likes as $like)
{
$insert3 = "insert into ProfileInterests " .
"values ('$id', '$like', null)";
$result3 = # mysql_query ($insert3, $connection)
or showerror();
}
mysql_close($connection)
or showerror();
For some reason this does not work =/ I don't know why. $likes is an array which was a user input. I need it to insert into the table it multiple times until all of the things in the array are in.
EDIT I fixed the issue where I was closing it in my foreach loop. mysql_open is my own function btw.
Any ideas?
For one $likes is an empty array in your example, I am assuming you fix that in the code you run.
The second is you close the MySQL connection the first the time the loop would run, which would prevent subsequent MySQL queries from running.
there's no such function as mysql_open
you may need mysql_connect
also $likes variable is empty. so no foreach iterations will execute.
You close the connection within the foreach loop.
Here is the proper formatted code to insert data...You can use this.
// DATABASE CONNECTION
$conn=mysql_connect(HOST,USER,PASS);
$link=mysql_select_db(DATABASE_NAME,$conn);
// function to insert data ..here $tableName is name of table and $valuesArray array of user input
function insertData($tableName,$valuesArray) {
$sqlInsert="";
$sqlValues="";
$arrayKeys = array_keys($valuesArray);
for($i=0;$i < count($arrayKeys);$i++)
{
$sqlInsert .= $arrayKeys[$i].",";
$sqlValues .= '"'.$valuesArray[$arrayKeys[$i]].'",';
}
if($sqlInsert != "")
{
$sqlInsert = substr($sqlInsert,0,strlen($sqlInsert)-1);
$sqlValues = substr($sqlValues,0,strlen($sqlValues)-1);
}
$sSql = "INSERT INTO $tableName ($sqlInsert) VALUES ($sqlValues)";
$inser_general_result=mysql_query($sSql) or die(mysql_error());
$lastID=mysql_insert_id();
$_false="0";
$_true="1";
if(mysql_affected_rows()=='0')
{
return $_false;
}
else
{
return $lastID;
}
}
// End Of Function
While many PHP newbies (myself included) begin working with databases from good ole' mysql_connect/query/etc., I can't help suggest that you look into PDO, PHP Data Objects. Depending on your prior knowledge and programming background, there may be a steeper learning curve. However, it's much more powerful, extensible, etc.; I use PDO in all my production code database wheelings-and-dealings now.
In PHP, I want to insert into a database using data contained in a associative array of field/value pairs.
Example:
$_fields = array('field1'=>'value1','field2'=>'value2','field3'=>'value3');
The resulting SQL insert should look as follows:
INSERT INTO table (field1,field2,field3) VALUES ('value1','value2','value3');
I have come up with the following PHP one-liner:
mysql_query("INSERT INTO table (".implode(',',array_keys($_fields)).") VALUES (".implode(',',array_values($_fields)).")");
It separates the keys and values of the the associative array and implodes to generate a comma-separated string . The problem is that it does not escape or quote the values that were inserted into the database. To illustrate the danger, Imagine if $_fields contained the following:
$_fields = array('field1'=>"naustyvalue); drop table members; --");
The following SQL would be generated:
INSERT INTO table (field1) VALUES (naustyvalue); drop table members; --;
Luckily, multiple queries are not supported, nevertheless quoting and escaping are essential to prevent SQL injection vulnerabilities.
How do you write your PHP Mysql Inserts?
Note: PDO or mysqli prepared queries aren't currently an option for me because the codebase already uses mysql extensively - a change is planned but it'd take alot of resources to convert?
The only thing i would change would be to use sprintf for readability purposes
$sql = sprintf(
'INSERT INTO table (%s) VALUES ("%s")',
implode(',',array_keys($_fields)),
implode('","',array_values($_fields))
);
mysql_query($sql);
and make sure the values are escaped.
Nothing wrong with that. I do the same.
But make sure you mysql_escape() and quote the values you stick in the query, otherwise you're looking at SQL injection vulnerability.
Alternately, you could use parametrized queries, in which case you can practically pass the array in itself, instead of building a query string.
The best practice is either to use an ORM (Doctrine 2.0), an ActiveRecord implementation (Doctrine 1.0, RedBean), or a TableGateway pattern implementation (Zend_Db_Table, Propel). These tools will make your life a lot easier, and handle a lot of the heavy lifting for you, and can help protect you from SQL injections.
Other than that, there's nothing inherently wrong with what you're doing, you just might want to abstract it away into a class or a function, so that you can repeat the functionality in different places.
Using the sprintf trick mentioned by Galen in a previous answer, I have come up with the following code:
$escapedfieldValues = array_map(create_function('$e', 'return mysql_real_escape_string(((get_magic_quotes_gpc()) ? stripslashes($e) : $e));'), array_values($_fields));
$sql = sprintf('INSERT INTO table (%s) VALUES ("%s")', implode(',',array_keys($_fields)), implode('"," ',$escapedfieldValues));
mysql_query($sql);
It generates a escaped and quoted insert. It also copes independent of whether magic_quotes_gpc is on or off. The code could be nicer if I used new PHP v5.3.0 anonymous functions but I need it to run on older PHP installations.
This code is a bit longer that the original (and slower) but it is more secure.
I use this to retrieve the VALUES part of the INSERT.
But it might be an absurd way to do things. Comments/suggestions are welcome.
function arrayToSqlValues($array)
{
$sql = "";
foreach($array as $val)
{
//adding value
if($val === NULL)
$sql .= "NULL";
else
/*
useless piece of code see comments
if($val === FALSE)
$sql .= "FALSE";
else
*/
$sql .= "'" . addslashes($val) . "'";
$sql .= ", ";
};
return "VALUES(" . rtrim($sql, " ,") . ")";
}
There is a problem with NULL (in the accepted answer) values being converted to empty string "". So this is fix, NULL becomes NULL without quotes:
function implode_sql_values($vals)
{
$s = '';
foreach ($vals as $v)
$s .= ','.(($v===NULL)?'NULL':'"'.mysql_real_escape_string($v).'"');
return substr($s, 1);
}
Usage:
implode_sql_values(array_values( array('id'=>1, 'nick'=>'bla', 'fbid'=>NULL) ));
// =='"1","bla",NULL'
If you want to enhance your approach and add the possibility for input validation and sanitation, you might want to do this:
function insertarray($table, $arr){
foreach($arr as $k => $v){
$col[] = sanitize($k);
$val[] = "'".sanitize($v)."'";
}
query('INSERT INTO '.sanitize($table).' ('.implode(', ', $col).') VALUES ('.implode(', ', $val).')' );
}