Issue with bulk insert in mysql using pdo and php - php

I am trying to insert bulk records in mysql using pdo but for some reason I am not able to build up the query.
My POST looks like this
Array
(
[ques_1] => dsadasd
[ques_2] => 5
[ques_3] => dasdsad
[ques_4] => 23/7/2014
[savecontinue] => Save & Continue
)
My desired array should look like this
Array
(
[quid] => 1
[answer] => dasdsad
)
Array
(
[quid] => 2
[answer] => on
)
Array
(
[quid] => 3
[answer] => dasdsad
)
Array
(
[quid] => 4
[answer] => 23/7/2014
)
My code looks like this
foreach($_POST as $k=>$v)
{
if($k != 'savecontinue' and $k != 'skipsave')
{
list(,$qid) = explode("_",$k);
$insertData[$qid] = $v;
}
}
$sql = "INSERT INTO answers (quid, answer)
VALUES (:quid, :answer)";
$query = $this->db->prepare($sql);
$query->execute($insertData);
The error is PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
Note: I have simplified/reduced the query params and code for better understanding.

Well it seems to me that you would be better of with something like this.
You also were passing to many parameters to the INSERT, the array you pass must have only those values required by the query and be named with the ':' in front.
// prepare the query for multiple use later
$sql = "INSERT INTO answers (userid, catid, quid, qstep, answer)
VALUES (:userid, :catid, :quid, :qstep, :answer)";
$query = $this->db->prepare($sql);
// create an array of inputs
for ($x=1; $x < 5; $x++ ) {
$insertData[] = array( ':userid' => 1,
':catid' => $_POST['catid'],
':quid' => $x,
':qstep' => 1,
':answer' => $_POST['ques_'.$x]);
}
// loop over the array of inputs
foreach ( $insertData as $data ) {
$query->execute($data);
}

Change the following:
$insertData = array("$qid"=>"$v");
to:
$insertData[$qid] = $v;

Related

Insert into MySQL from array into two tables at once based on some conditions

I have this array with data rows from an excel file used with SimpleXLSX in php check https://github.com/shuchkin/simplexlsx,
Working just fine, but the thing is that i want all the datas to insert them into two MySQL tables
In table 1 it's ok, but in table 2 it's the problem, I want to take all the last inserted IDs entered from table 1 and insert them in table 2 with dansatori IDs which is an array if you look at the SimpleXLSX output at [dansatori]
Please check this image to see what i want to achive:
MySQL Tables
Array SimpleXLSX output in PHP:
Array
(
[0] => Array
(
[numecoregrafie] => Vampire Dance
[niveldans] => 2
[coregraf] => Damon Salvatore
[sectiuni] => 1
[disciplina] => 7
[catvarsta] => 6
[dansatori] => Array
(
[0] => 84
[1] => 86
)
[nrdansatori] => 2
)
[1] => Array
(
[numecoregrafie] => End of the world
[niveldans] => 1
[coregraf] => Stephany
[sectiuni] => 2
[disciplina] => 14
[catvarsta] => 4
[dansatori] => Array
(
[0] => 82
[1] => 87
)
[nrdansatori] => 2
)
[2] => Array
(
[numecoregrafie] => Slapping Chris Rock
[niveldans] => 2
[coregraf] => Will Smith
[sectiuni] => 1
[disciplina] => 13
[catvarsta] => 18
[dansatori] => Array
(
[0] => 84
)
[nrdansatori] => 1
)
)
Wthat i have tried so far:
$file = "MomenteMultiple_RDCP_2.xlsx"; // The excel file
$xlsx = new SimpleXLSX( $file ); // SimpleXLSX object
$dns = array();
$skip = 1;
$dansatori = array();
$lastID = array();
foreach ($xlsx->rows() as $key => $fields)
{
if($skip !=1) // Skipping the first row from XLSX file.
{
if($fields[7] > 0) {
$rowValue = !empty($fields) && $fields != "" ? $fields : 'null';
$result = array_filter($rowValue); // remove empty values from array
$values = explode(",", $result[6]); // explode string into array
$dancersIDS = array_filter($values);
$dns[] = [
'numecoregrafie' => $result[0],
'niveldans' => $result[1],
'coregraf' => $result[2],
'sectiuni' => $result[3],
'disciplina' => $result[4],
'catvarsta' => $result[5],
'dansatori' => $dancersIDS,
'nrdansatori' => $result[7],
'uid' => $user->filter->id
]; // Add the values to the array
}
}
$skip++; // Increment the skip value
}
// Table 1
$query =
'INSERT INTO `rdcp_momente`
(numecoregrafie,
niveldans,
coregraf,
sectiuni,
disciplina,
catvarsta,
nrdansatori
) VALUES'; // Query to insert values into table 1
// Table 2
$queryd =
'INSERT INTO `rdcp_dansatorim`
(`did`,
`uid`,
`mid`
) VALUES'; // Query to insert values into table 2
foreach($dns as $d) {
$query .= "
(
'".$d['numecoregrafie']."',
'".$d['niveldans']."',
'".$d['coregraf']."',
'".$d['sectiuni']."',
'".$d['disciplina']."',
'".$d['catvarsta']."',
'".$d['nrdansatori']."'
),"; // Query to insert values into table 1
foreach($d['dansatori'] as $dansator)
{
$queryd .= "
(
'".$dansator."',
'".$user->filter->id."',
'".$lastID."'
),"; // LastID is the last inserted id of the table 1
}
}
$query = rtrim($query, ","); // remove last comma
$queryd = rtrim($queryd, ",");
$query .= ";";
$queryd .= ";";
$db->query($query); // insert into table 1
$lastID[] = $db->insertId(); // get the last inserted id
$db->query($queryd); // insert into table 2
echo '<pre>';
echo var_dump($query);
echo '<pre>';
echo var_dump($queryd);
Only one ID inserted instead of all ids that corresponds with last inserted rows
Prepare your INSERT statements
Bind parameters
Iterate over the data
Execute your first statement
Get the last insert ID
Iterate over the dansatori index
Execute your second statement
Because mysqli_stmt::bind_param takes variable references, you can prepare and bind parameters before you start iterating your data.
$stmt1 = $db->prepare('INSERT INTO `rdcp_momente` (numecoregrafie, niveldans, coregraf, sectiuni, disciplina, catvarsta, nrdansatori) VALUES (?, ?, ?, ?, ?, ?, ?)');
// you might want to tweak the parameter types
$stmt1->bind_param('sssssss',
$d['numecoregrafie'],
$d['niveldans'],
$d['coregraf'],
$d['sectiuni'],
$d['disciplina'],
$d['catvarsta'],
$d['nrdansatori']);
$stmt2 = $db->prepare('INSERT INTO `rdcp_dansatorim` (`did`, `uid`, `mid`) VALUES (?, ?, ?)');
$stmt2->bind_param('ssi', $dansator, $user->filter->id, $lastId);
foreach ($dns as $d) {
$stmt1->execute();
$lastId = $db->insert_id;
foreach($d['dansatori'] as $dansator) {
$stmt2->execute();
}
}

Array not being parsed correctly

Having issues with an array being parsed..
Here is a dump from the $_GET var
Array
(
[perm0] => Array
(
[0] => View
[1] => Add
[2] => Edit
[3] => Delete
[4] => Export
)
[perm1] => Array
(
[0] => View
[1] => Add
[2] => Export
)
[add] =>
)
When I try and use a foreach to insert into the db its only inserting the first item.
I am need to add the number based on the perm[] value such as perm0, perm1 etc
Here is my code
$i = 0;
$id = 0;
foreach($_GET['perm'.$i] as $permission)
{
do {
$perms = implode(":",$_GET['perm'.$i]);
mysqli_query($dbc,"INSERT INTO `permissions` (`mid`,`uid`,`permissions`) VALUES ('$id','99','$perms')");
echo mysqli_error($dbc);
} while(strpos($permission, $i) !== false);
$id++;
$i++;
}
I would have thought this would be really simple so I dont know why I'm having issues with it
The problem is that you are always only looking at the first item, your statement...
foreach($_GET['perm'.$i] as $permission)
will only ever pick up the perm0 item, even though you increment $i in the loop.
Instead, this code loops over all $_GET values, checks if they are the permN values and then inserts the value. I've also converted to prepared statements to add some level of security...
$i = 0;
$insert = mysqli_prepare ($dbc,"INSERT INTO
`permissions` (`mid`,`uid`,`permissions`)
VALUES (?,'99',?)");
foreach ( $_GET as $key => $param ) {
if ( $key == "perm$i" ) {
$perms = implode(":",$param);
mysqli_stmt_bind_param ($insert, "is", $i, $perms);
mysqli_execute($insert);
$i++;
}
}
As it's difficult for me to test this, please let me know if you have issues.

How to insert multiple dynamic rows into the database

I have a multiple row dynamic table that I created using php and jQuery. Here's the link to view the table.
Everything is working fine except when I insert the data into the database, the serial numbers do not save sequentially. My insert queries are as below:
for($i = 0; $i < count($_POST['C_Objectives']); $i++)
{
$sql = "INSERT INTO Appraisal_Objectives (Serial_Number,Objectives,Measures,Targets,subtotal,Corporate_Objective,Row_Number,ID) Values ('$formno','||<==','==','==','".$_POST['SubTotals'][$i]."','".$_POST['C_Objectives'][$i]."','".$_POST['SNo'][$i]."','$statement')";
$stmt = sqlsrv_query($conn, $sql);
if($stmt === false)
die(print_r(sqlsrv_errors(), true));
else
echo " ";
}
for($i = 0; $i < count($_POST['Measures']); $i++)
{
$sql = "INSERT INTO Appraisal_Objectives (Serial_Number,Objectives,Measures,Targets,Weightage,Row_Number,target_date,ID) VALUES ('$formno','".$_POST['Objectives'][$i]."','".$_POST['Measures'][$i]."','".$_POST['Achievement'][$i]."','".$_POST['Weightage_Target'][$i]."','".$_POST['SNo'][$i]."','".$_POST['Date_Target'][$i]."','$statement')";
$stmt = sqlsrv_query($conn, $sql);
if($stmt === false)
die(print_r(sqlsrv_errors(), true));
else
echo " ";
}
The serial number is saved in the column Row_Number, using $_POST['SNo'][$i]. Is it possible to save both of the dynamic rows using 1 insert query so that the serial numbers are saved sequentially?
This is the $_POST array result:
[Row_Number] => Array
(
[0] => 1
[1] => 2
)
[C_Objectives] => Array
(
[0] => A
[1] => B
)
[Objectives] => Array
(
[0] => a1
[1] => a4
[2] => a7
[3] => b1
)
[Measures] => Array
(
[0] => a2
[1] => a5
[2] => a8
[3] => b2
)
[Achievement] => Array
(
[0] => a3
[1] => a6
[2] => a9
[3] => b3
)
[Date_Target] => Array
(
[0] => 2016-09-09
[1] => 2016-09-09
[2] => 2016-09-09
[3] => 2016-09-09
)
[Weightage_Target] => Array
(
[0] => 25
[1] => 25
[2] => 25
[3] => 25
)
[SNo] => Array
(
[0] => 3
[1] => 4
[2] => 5
[3] => 6
)
[SubTotals] => Array
(
[0] => 75
[1] => 25
)
[GrandTotal] => 100
)
I've also tried making the column auto-increment, but yet doesn't save the data in the same order as it is entered in the front end.
Your inserting has performance issue. Please change your way for inserting to the database. You can do all of them in one query. Even if you have 20 loop for first "for" and 20 loop for 2nd "for".
Answer to What you asked
If you want to insert by $_POST['SNo'] order, change this line
for($i = 0; $i < count($_POST['C_Objectives']); $i++)
to the
foreach($_POST['SNo'] as $i)
If you need multiple insert at once, just do this:
INSERT INTO Appraisal_Objectives (Serial_Number,Objectives,...)
VALUES (Value1,Value2,...), (Value1,Value2,...)
This is What you MUST do
In your code, you did the same query in 6 queries. It can even be more than 6 with more $_POST['Measures'] or $_POST['C_Objectives'] array length.
You need to Put them in one query and when you don't need to set the value, just set it to the column default value. for example NULL
Something like this:
//first we create $values array. it contains all values that you need to insert to the db
$values = array();
$j=0;
for($i = 0; $i < count($_POST['C_Objectives']); $i++){
$values[$j]['Serial_Number'] = $formno;
$values[$j]['Objectives'] = '||<==';
//and fill others here
//fill all cols that you wrote inside your query with the correct order
$j++;
}
for($i = 0; $i < count($_POST['Measures']); $i++){
$values[$j]['Serial_Number'] = $formno;
$values[$j]['Objectives'] = $_POST['Objectives'][$i];
//and fill others here
//fill all cols that you wrote inside your query with the correct order
$j++;
}
//now create (value1,value2,...),(value1,value2,...),...
$query = NULL;
foreach($values as $value){
$tmp = NULL;
foreach($value as $v){
$tmp .= ($v=='')? 'NULL,' : "'$v',";
}
$tmp = rtrim($tmp,',');
$query .= "($tmp),";
}
$query = rtrim($query,',');
//Now Insert
$sql = "INSERT INTO Appraisal_Objectives (Serial_Number,Objectives,...) VALUES $query";
In this example I just showed you how to do it. Remember, you must check $v and prepare it by your column type. check if $_POST[KEY] is set and it's array. Don't insert to the database if $query is empty.
Very Important about your codes
If this is not your original code there is no problem but if it is, please change the way you are using $_POST inside your query. It has very low security. at least you need to validate them before using it.
Yes you can able to insert in single insert query.
$arrMeasuresInsData = array();
for($i = 0; $i < count($_POST['C_Objectives']); $i++) {
$sql = "INSERT INTO Appraisal_Objectives (Serial_Number, Objectives, Measures, Targets, subtotal, Corporate_Objective, Row_Number, ID, Weightagen, target_date)
Values ('$formno',
'||<==',
'==',
'==',
'".$_POST['SubTotals'][$i]."',
'".$_POST['C_Objectives'][$i]."',
'".$_POST['SNo'][$i]."',
'$statement',
'',
'')";
if(!empty($_POST['Measures'][$i])) {
$arrMeasuresInsData[$i] = $_POST['Measures'][$i];
$sql .= ",('$formno',
'".$_POST['Objectives'][$i]."',
'".$_POST['Measures'][$i]."',
'".$_POST['Achievement'][$i]."',
'',
'',
'".$_POST['SNo'][$i]."',
'".$_POST['Date_Target'][$i]."',
'".$_POST['Weightage_Target'][$i]."',
'$statement',)";
}
$stmt = sqlsrv_query($conn, $sql);
if($stmt === false)
{
die(print_r(sqlsrv_errors(), true));
}
else
{
echo " ";
}
}
for($i = 0; $i < count($_POST['Measures']); $i++) {
if(isset($arrMeasuresInsData[$i])) {
continue;
}
$sql="INSERT INTO Appraisal_Objectives (Serial_Number,Objectives,Measures,Targets,Weightage,Row_Number,target_date,ID)
VALUES ('$formno',
'".$_POST['Objectives'][$i]."',
'".$_POST['Measures'][$i]."',
'".$_POST['Achievement'][$i]."',
'".$_POST['Weightage_Target'][$i]."',
'".$_POST['SNo'][$i]."',
'".$_POST['Date_Target'][$i]."',
'$statement')";
$stmt = sqlsrv_query($conn, $sql);
if($stmt === false)
{
die(print_r(sqlsrv_errors(), true));
}
else
{
echo " ";
}
}
I think you are getting your $_POST array wrongly. You have to change the input form and recieve the input some thing like below:
[C_Objectives] => Array
(
[Row_Number] => Array
(
[title] => 'xxx',
[0] => Array
(
[0] => Array
(
[SNo] => 2
[Objectives] => a1,
[Measures] => a2,
[Achievement] => a3,
[Date_Target] => 2016-09-09,
[Weightage_Target] => 25
),
(
[SNo] => 3
[Objectives] => a1,
[Measures] => a2,
[Achievement] => a3,
[Date_Target] => 2016-09-09,
[Weightage_Target] => 25
),
(
[SNo] => 4
[Objectives] => a1,
[Measures] => a2,
[Achievement] => a3,
[Date_Target] => 2016-09-09,
[Weightage_Target] => 25
),
[SubTotals] => 75
)
)
},
(
[Row_Number] => Array
(
[title] => 'xxx',
[0] => Array
(
[0] => Array
(
[SNo] => 6
[Objectives] => a1,
[Measures] => a2,
[Achievement] => a3,
[Date_Target] => 2016-09-09,
[Weightage_Target] => 25
),
[SubTotals] => 25
)
)
)
Above is the only example rest you have to understand how to do that.
As it would be difficlut to know which value belong to which row it might be possible that value defined as 2nd below to 3rd row.
With the current code, there will be at least two INSERT statements, and more when $_POST['Measures'] or $_POST['C_Objectives'] contain a larger number of elements.
You can insert multiple records with one statement, and instead of using a for statement, use a foreach so you don't have to do the bookkeeping on the iterator variable. Then store values in arrays and use implode() to combine the sets of values for each record.
Check which values are being inserted into which columns - it appears that in the first for loop of your example, you are inserting the value from $_POST['SNo'][$i] into the ID field...
$values = array();
foreach($_POST['C_Objectives'] as $index=>$value) {
$rowValues = array();
$rowValues[] = $_POST['SNo'][$index]; //Serial_Number
array_push($rowValues,$formno,'||<==','==','=='); //, Objectives, Measures, Targets, subtotal
$rowValues[] = $_POST['SubTotals'][$index]; //Corporate_Objective
$rowValues[] = $value; //Row_Number: $value == $_POST['C_Objectives'][$index];
$values[] = "('".implode("', '",$rowValues )."')";
}
$fields = array('Objectives','Measures','Achievement','Weightage_Target','SNo','Date_Target');
foreach($_POST['Measures'] as $index=>$value) {
$rowValues = array($formno);
foreach($fields as $field) {
$rowValues[] = $_POST[$field][$index];
}
$values[] = "('".implode("', '",$rowValues )."')";
}
$sql = "INSERT INTO Appraisal_Objectives (Serial_Number,Objectives,Measures,Targets,subtotal,Corporate_Objective,Row_Number,ID) VALUES ".implode(', ',$values);
$stmt = sqlsrv_query($conn, $sql);
if($stmt === false) {
die(print_r(sqlsrv_errors(), true));
}
else {
echo " ";
}
what are you going to do? Two loop execution is different insertion .....
Solution:
1. The second update operation.
2. organize the data into the database at once.

PHP - Compaire Two Multidimensional Arrays and Append to One Array Accordingly

Today I'm having a bit of trouble figuring out a few things in PHP. As I normally do have the tendency to ramble a bit, I will try to keep my question short but concise. Here's what I'm trying to do.
Array #1 is a multidimensional array containing the results from MySQL query done against a user table in the database. It would look as such:
Array ( [0] => Array ( [id] => 79 [firstname] => John [lastname] => Doe [province] => Province [email] => someemail#gmail.com [primaryphone] => 123-456-7890 ) [1] => Array ( [id] => 113 [firstname] => Jane [lastname] => Doe [province] => Province [email] => email#gmail.com [primaryphone] => 123-456-7890 ) )
Array #2 is another multidimensional array containing the results from a MySQL query done against a membership table in the database that contains the id of the user that is associated with the current group. It looks as follows:
Array ( [0] => Array ( [userid] => 79 ) [1] => Array ( [userid] => 115 ) [2] => Array ( [userid] => 124 ) )
What I am trying to do, is for every user returned in array #1, look for a value in array #2 under [userid] that matches the value [id] in array #1. If a match is found for each user, append the key and value [ismember] => 1 for that user in array #1 - if there is not a match, then append the pair [ismember] => 0 to array #1.
I feel that this should be a very simple process, and I'm probably just missing something that is elementary... But I've been going at it for a while now and haven't made much progress. Thank you all for your time and help.
== EDIT ==
The first array is generated by the following MySQL Query:
$query = "
SELECT
id,
firstname,
lastname,
province,
email,
primaryphone
FROM userstable
";
try
{
$stmt = $db->prepare($query);
$stmt->execute();
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$allusersdetails = $stmt->fetchAll();
The second array is generated by the query:
$query = "
SELECT
userid
FROM membershipstable
WHERE templateid = :currenttemplateid
";
try
{
$stmt = $db->prepare($query);
$stmt->bindParam(':currenttemplateid', $currenttemplateid);
$stmt->execute();
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$templateusers = $stmt->fetchAll();
You can replace the 2 queries with one query like this:
$query = "
SELECT
u.id,
u.firstname,
u.lastname,
u.province,
u.email,
u.primaryphone,
(CASE WHEN m.userid IS NULL THEN 0 ELSE 1 END) AS ismember
FROM userstable AS u
LEFT JOIN membershipstable AS m ON
m.templateid = :currenttemplateid AND
u.id = m.userid
";
try
{
$stmt = $db->prepare($query);
$stmt->bindParam(':currenttemplateid', $currenttemplateid);
$stmt->execute();
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$allusersdetails = $stmt->fetchAll();
This will still pull all users, whether they are members or not but, it will add ismember as column.
(the AS x part of userstable AS u and membershipstable AS m just assigns the letter as an alias of the table for the duration of the SELECT. Basically, it mostly helps you save on typing but also lets you JOIN on tables with columns of the same name.)
Welcome to the wonderful world of Structured Query Languages :D
EDIT
And just in case someone comes here trying to do exactly what the question title is asking for but doesn't happen to be querying the database but does have a arrays in the exact format that the OP had:
<?php
$array =
Array ( 0 => Array ( 'id' => '79','firstname' => 'John','lastname' => 'Doe','province' => 'Province','email' => 'someemail#gmail.com','primaryphone' => '123-456-7890',), 1 => Array ( 'id' => '113','firstname' => 'Jane','lastname' => 'Doe','province' => 'Province','email' => 'email#gmail.com','primaryphone' => '123-456-7890',) )
;
$array2 =
Array ( 0 => Array ( 'userid' => '79'), 1 => Array ( 'userid' => '115'), 2 => Array ( 'userid' => '124') );
foreach($array as $key => $userInfo) {
$isMember = 0;
foreach($array2 as $user) {
if($userInfo['id'] == $user['userid']) {
$isMember = 1;
break;
}
}
$array[$key]['ismember'] = $isMember;
}
Try this,
$firstArray = //your first array
$secondArray = // your second array
foreach($firstArray as $fa) {
$id = $fa['id'];
}
foreach($secondArray as $sa) {
$userId = $sa['userid'];
}
if($id === $userID) {
$firstArray['ismember'] = 1;
} else {
$firstArray['ismember'] = 0;
}

PDO prepared statement not returning correct results (returns array filled with the variable name)

Been looking for ages how to get this prepared statement to work using both ? placeholders and named placeholders but no joy.
here is the code I have ended up with
<?php
require_once ("connection.php");
global $db;
$one = 'ID';
//$two = "QA-A";
$st = $db->prepare('select ? from EXECUTION_HISTORY');
//$array = array("ID", "QA-A");
$st->bindParam(1, $one, PDO::PARAM_STR);
//$st->bindParam(':two', $two);
$st ->execute();
$data = $st->fetchAll(PDO::FETCH_ASSOC);
print_r($data);
and this is the result it prints out
Array ( [0] => Array ( [ID] => ID ) [1] => Array ( [ID] => ID ) [2] => Array ( [ID] => ID )
if I change the select statement to
$st = $db->prepare('select ID from EXECUTION_HISTORY');
I get the real result
Array ( [0] => Array ( [ID] => 4 ) [1] => Array ( [ID] => 52 ) [2] => Array ( [ID] => 53 )
Can anyone see where I am going wrong?
Thanks
With bindParam You're (surprise) binding a parameter to a placeholder in the query, not a field. Your prepared statement is actually prepared to this:
SELECT 'ID' FROM EXECUTION_HISTORY
Knowing this it is not strange you're getting the result you get.
So you don't need a paceholder here. But you do want some sanitizing and checks built in your query.
The way I do these things mostly is following:
$field = 'ID'; // Or from $_GET or something
$good = array('ID'); //holding every allowed field
$field = (in_array($field, $good)) ? $field : false;
if($field){
$sql = "SELECT $field FROM EXECUTION_HISTORY WHERE someOtherField = :value";
$stm = $dbConn->prepare($sql);
$stm->bindParam(':value', $value, PDO::PARAM_STR);
$stm->execute();
print_r($stm->fetchAll());
}else{
echo "Field is not allowed";
}

Categories