PDO SQL single query, multiple rows and values - php

I have this array JSON POST request to a PHP file.
Array
(
[user_id] => 1
[date] => 2014-12-05
[time] => 12:00
[description] => lol
[friends] => "12","9"
[PHPSESSID] => 5ae7c3e6339c528e7804020dd0f0cdbb
)
I try to add the values (12 | 1) and (9 | 1) to a mysql table with a single sql query
Table:
u_id | f_id
1 | 12
1 | 9
What I have so far:
$friendarray = $_POST['Friends'];
foreach( $friends as $friendsarray ) {
$values[] = "(" . $u_id . "," . $friendsarray . ")";
}
$query = "INSERT INTO up2_friends_to_users (u_id , f_id ) VALUES ".implode(',',$values);
$stmt = $db->prepare($query);
$result = $stmt->execute();
As you see this is not working at all. I try to achieve something like this:
$query_params = array(
':u_id' => $_POST['user_id'],
':f_id' => $friendid,
And then would like to send it like this:
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
Is it possible to create a single query with multiple rows like this?
Answer thanks to RobP:
$friendsarray = explode(',',$_POST['friends']);
$placeholders = [];
for($i=0, $len=count($friendsarray); $i < $len; $i++) {
$placeholders[i] .= "(:u_id".$i.", :f_id".$i.")"; // entries like "(:u_id0, :f_id0)"
}
$query = "INSERT INTO up2_friends_to_users (u_id , f_id ) VALUES ".implode(",", $placeholders);
$stmt = $db->prepare($query);
for($i=0, $len=count($placeholders); $i < $len; $i++) {
$stmt->bindParam(':u_id'.$i, $_POST['user_id']);
$nextFriend = $friendsarray[$i];
$stmt->bindParam(':f_id'.$i,trim($nextFriend,'"'));
}
$result = $stmt->execute();
Now f_id is always null.

I agree the best strategy is to use a single query as you were trying to do. This will be much faster for long lists, especially if you don't wrap all the individual inserts into a single commit. This should work:
$friendarray = $_POST['Friends'];
$placeholders = [];
$user_id = $_POST[`user_id`];
for($i=0, $len=count($friendarray); $i < $len; $i++) {
$placeholders[$i] = "(:u_id".$i.", :f_id".$i.")"; // entries like "(:u_id0, :f_id0)"
}
$query = "INSERT INTO up2_friends_to_users (u_id , f_id ) VALUES ".implode(",", $placeholders);
$stmt = $db->prepare($query);
for($i=0, $len=count($placeholders); $i < $len; $i++) {
// each binding must use a separate variable, not an array element
$stmt->bindParam(':u_id'.$i, $user_id);
// use your favorite escape function on the value here
$nextFriend = $db->real_escape_string($friendarray[$i]);
$stmt->bindValue(':f_id'.$i, $nextFriend);
}
EDIT: learned something new from Only variables can be passed by reference - php. Can't pass array elements to bindParam as second parameter! Workaround posted above.

Do this:
$query = "INSERT INTO up2_friends_to_users (u_id , f_id ) VALUES (:u_id, :f_id)";
$stmt = $db->prepare($query);
$stmt->bindParam(':u_id', $_POST['user_id'];
$stmt->bindParam(':f_id', $friendid);
foreach ($_POST['Friends'] as $friendid) {
$stmt->execute();
};
bindParam binds to a reference, so every time you execute the query it will use the value of $friendid from the current iteration of the loop.

Maybe, something like this (using question mark parameters)?
$values = array();
foreach ($_POST['Friends'] as $friendid) {
$values[] = $u_id;
$values[] = $friendid;
}
$conn = new \PDO($dsn, $user, $password);
$query = 'INSERT INTO up2_friends_to_users (u_id , f_id ) VALUES '
. trim(str_repeat('(?, ?),', count($values / 2)), ',');
$conn->prepare($query)->execute($values);

Related

Collect values from JSON file for use in MySQL `IN` clause

include "includes/dbh.inc.php";
$data = file_get_contents("dumps/datadump-hung1.json");
$post = json_decode($data, true);
foreach($post['sessionResult']['leaderBoardLines'] as $userArr){
$carname .=$userArr['car']['carModel'];
} echo $carname;
this echoes out the carmodel numbers like this= 19115 instead of 19 1 15
when i try to match these with my database to echo out the name of cars the numbers respond to with:
$carGETdb = "SELECT carName FROM cars WHERE carID IN ($carname)";
$result = mysqli_query($conn, $carGETdb);
$row = mysqli_fetch_array($result)["carName"];
echo $row;
it posts nothing, because no cars is associated with 19115 but 3 different cars is associated with 19, 1 and 15
is there a way to foreach each array in singles, so i can match them with my database and echo out as carnames instead of numbers?
Map the values you're after to a new array
Build a prepared statement with the appropriate number of ? parameters in your IN clause
Bind the array of values to your statement
Execute and fetch
$carIds = array_map(function($userArr) {
return $userArr['car']['carModel'];
}, $post['sessionResult']['leaderBoardLines']);
// [ 19, 1, 15 ]
$placeholders = implode(', ', array_fill(0, count($carIds), '?'));
// "?, ?, ?"
$bindTypes = str_repeat('i', count($carIds));
// "iii"
$stmt = $conn->prepare(
"SELECT `carID`, `carName` FROM `cars` WHERE `carID` IN ($placeholders)");
$stmt->bind_param($bindTypes, ...$carIds);
$stmt->execute();
$stmt->bind_result($carId, $carName);
$carNames = [];
while ($stmt->fetch()) {
$carNames[$carId] = $carName;
}
var_dump($carNames);
Using your code...
include "includes/dbh.inc.php";
$data = file_get_contents("dumps/datadump-hung1.json");
$post = json_decode($data, true);
$carname = [];
foreach($post['sessionResult']['leaderBoardLines'] as $userArr){
$carname[] = $userArr['car']['carModel'];
}
$carnames = implode(',', $carname);
echo $carnames;
Then with your following statement when querying the database, you can use the implded value ( but this is bound to sql injection attacks ). You should use parameterised query instead. However, I am not going to change too much of your code so you can see what is going on.
$carGETdb = "SELECT carName FROM cars WHERE carID IN ($carnames)";
$result = mysqli_query($conn, $carGETdb);
$row = mysqli_fetch_array($result)["carName"];
echo $row;

Store multiple row table into array to allow for user updates

I have struggled with this concept for a while and am hoping someone can help, please. I can query database records if all values are stored in one row. The challenge I have is when the quantity values are stored on multiple rows but with a common key (e.g. order_id). I want to store into an array and then assign each value to an on-screen variable to allow user updates so that I can update the table again.
For example, if the table looks as follows:
id line part qty
-- ---- ---- ---
1 1 63 2
1 2 104 3
1 3 54 2
1 4 50 1
I have not had success with the following where I establish the number of rows and then try to build a foreach loop to capture the data:
$sql = 'SELECT *, COUNT(*) as $count FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$data = $q->fetch(PDO::FETCH_ASSOC);
for ($x = 0; $x <= $count; $x++ {
$var($x) = $data['qty'];
}
If I can properly separate the values into an array and then reference them somehow, then I could do the following and get them displayed and easily update back to the database:
$var_1 = $data['63']; // part_id = 63
$var_2 = $data['104']; // part_id = 104
$var_3 = $data['54']; // part_id = 54
$var_4 = $data['50']; // part_id = 50
Change this:
$sql = 'SELECT *, COUNT(*) as $count FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$data = $q->fetch(PDO::FETCH_ASSOC);
for ($x = 0; $x <= $count; $x++ {
$var($x) = $data['qty'];
}
To something that makes sense like this
$sql = 'SELECT * FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
while(false !== ($row = $q->fetch(PDO::FETCH_ASSOC))){
echo $row['qty'];
};
UPDATE
$sql = 'SELECT * FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$array = [];
while(false !== ($row = $q->fetch(PDO::FETCH_ASSOC))){
$array['line_'.$row['line']] = $row;
};
UPDATE
The additional code that answers what I was looking for is as follows. Your answer was key to my understanding it all:
$sql = 'SELECT * FROM Order_Items where order_id = ?';
$q = $pdo->prepare($sql);
$q->execute(array($id));
$array = [];
while(false !== ($row = $q->fetch(PDO::FETCH_ASSOC))){
$qty['line_'.$row['line']] = $row['qty'];
};
$var_54 = $qty['line_54'];
$var_63 = $qty['line_63'];

Avoiding code repetition for MySQL queries (multiple while)

I have the following code:
<?php
include_once "connect.php";
$question_01 = mysqli_real_escape_string($con, $_POST['question_01']);
// $question_02 - $question_09 go here...
$question_10 = mysqli_real_escape_string($con, $_POST['question_10']);
$i = 0;
$array_sum=[];
while ($i < 10){
$i++;
$sql = "SELECT * FROM parteners WHERE question_no = 1 AND answer_variant = '$question_01'";
$result = mysqli_query($con, $sql);
$final_array_1 = array();
while ($row = mysqli_fetch_array($result, MYSQLI_NUM))
{
$final_array_1 = $row;
$array_sum = array_map(function () {
return array_sum(func_get_args());
}, $array_sum, $final_array_1);
}
}
print_r($final_array_1);
As you can see, I need to repeat the code for each $question_##. Is there a smarter way of doing this other than repeating the code? I'm not only concerned about turning everything into a code spaghetti but also about the efficiency of the operations as in loading times.
Let me know if you need clarification.
Update: Basically it should increase the value of "question_no" in the query until it reaches 10 and pick the corresponding $_POST value for each question.
There are two ways, variable variables or arrays. I'd suggest arrays as they are less prone to throwing errors everywhere.
<?php
include_once "connect.php";
$questions = array();
$questions[1] = mysqli_real_escape_string($con, $_POST['question_01']);
// $question_02 - $question_09 go here...
$questions[10] = mysqli_real_escape_string($con, $_POST['question_10']);
$i = 0;
$array_sum=[];
while ($i < 10){
$i++;
$sql = "SELECT * FROM parteners WHERE question_no = $i AND answer_variant = '".$questions[$i]."'";
$result = mysqli_query($con, $sql);
$final_array_1 = array();
while ($row = mysqli_fetch_array($result, MYSQLI_NUM))
{
$final_array_1 = $row;
$array_sum = array_map(function () {
return array_sum(func_get_args());
}, $array_sum, $final_array_1);
}
}
print_r($final_array_1);
EDIT: The reason I used an array instead of just straight up using the POST variable in the while loop is so there is room before you run anything for validation (ensuring your question array contains 10 posted values etc)
I would build one SQL-Statement which contains all questions and anwsers and do the rest with programming logic. SQL-Queries in a loop are a bad idea, because you have to do a lot of overhead for getting a task done, which the database server can do better. Also you should use prepared statements for performance and security.
$query = "SELECT * FROM parteners WHERE (question_no = 1 AND answer_variant = ?) OR (question_no = 2 AND answer_variant = ?) OR (question_no = 3 AND answer_variant = ?) OR (question_no = 4 AND answer_variant = ?) OR (question_no = 5 AND answer_variant = ?) OR (question_no = 6 AND answer_variant = ?) OR (question_no = 7 AND answer_variant = ?) OR (question_no = 8 AND answer_variant = ?) OR (question_no = 9 AND answer_variant = ?) OR (question_no = 10 AND answer_variant = ?)"
$stmt = myqli_prepare($query);
mysqli_stmt_bind_param($stmt, 'ssssssssss', $question_01, $question_02, $question_03,.....);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
First, to make your code modern and efficient, you should be using PHP
Data Objects, or PDO for short. You will have access to prepared
statements, which are made exactly for this: you build a query
"template" and execute with different data, very efficiently and secure.
The loop is the proper way to do it. Also, your $questions array is a
bit unecessary since you can retrieve data from $_POST right inside
your loop. But if you want to use it, there is no need to "escape" the
string for the database, since it's handled by PDO. So you can build
your array in a easier way:
$questions = [
$_POST['question_01'],
$_POST['question_02'],
$_POST['question_03'],
# ...
$_POST['question_10'],
];
Your loop with PDO:
$dbh = ... # create your database handle, connect to it
$st = $dbh->prepare("
SELECT * FROM parteners
WHERE question_no = ? AND answer_variant = ?;
");
foreach (range(1, 10) as $i) {
$result = $st->execute([ $i, $questions[$i-1] ]);
# or, to build directly
$result = $st->execute([
$i, $_POST[ sprintf("question_%02d", $i) ]
]);
$final_array[] = $result->fetchAll(PDO::FETCH_NUM);
}
print_r($final_array);

Writing to database using foreach

I have Three arrays and i want to write them to database , The issue I face is whenever the values are written to the particular column the rest of the column is left empty.
The
$name_array = array(3) { [0]"Name1" [1]=>"Name2" [2]=> "Name3" }
$roll_array = array(3) { [0]=>"1" [1]=>"2" [2]=>"3" }
$att_array = array(3) { [0]=>"Present" [1]=>"Present" [2]=>"absent" }
I have three columns in DB "NAME" "ROLL" "ATTENDANCE"
I want to store all the array data to the database at the same time.
so it should look like this
NAME ROLL ATTENDANCE
Name1 1 present
Name2 2 present
Name3 3 absent
Here is the code i tried but it just add each values to the column and leaves the other column empty. So the first three rows has only ROLLNO and next three row has only NAME and last three rows has only ATTENDANCE.
$name_values = array();
$roll_values = array();
$att_values = array();
foreach ($name_array as $key => $name_values) {
$name_values = mysqli_real_escape_string($connection,$name_values);
$sql= "INSERT INTO `aclass12` (Name) VALUES ('$name_values')";
mysqli_query($connection,$sql);
}
foreach ($roll_array as $key => $roll_values) {
$roll_values = mysqli_real_escape_string($connection,$roll_values);
$sql= "INSERT INTO `aclass12` (RollNo) VALUES ('$roll_values')";
}
foreach ($att_array as $key => $att_values) {
$att_values = mysqli_real_escape_string($connection,$att_values);
$sql= "INSERT INTO `aclass12` (attendance) VALUES ('$att_values')";
}
I know this is not the right way to do . and whats the way to do this ?
Simply use one array as the master, and the key of that array to access the other 2 arrays data.
Then insert all the data in a single INSERT
Its also a good idea to check that the INSERT actually worked, so I added a little bit of error checking
foreach ($name_array as $key => $value) {
$name = mysqli_real_escape_string($connection,$value);
$roll = mysqli_real_escape_string($connection,$roll_values[$key]);
$att = mysqli_real_escape_string($connection,$att_array[$key]);
$sql = "INSERT INTO `aclass12`
(Name, RollNo, attendance)
VALUES ('$value', '$roll', '$att')";
$res = mysqli_query($connection,$sql);
if ( $res === FALSE ) {
echo mysqli_error();
exit;
}
}
Use only one foreach and access the elements of the arrays there. Like this:
foreach ($name_array as $key => $name_values) {
$name_values = mysqli_real_escape_string($connection,$name_values);
$roll_values = mysqli_real_escape_string($connection,$roll_array[$key]);
$att_values = mysqli_real_escape_string($connection,$att_array[$key]);
$sql= "INSERT INTO `aclass12` (Name, RollNo, attendance) VALUES ('$name_values', '$roll_values', '$att_values')";
mysqli_query($connection,$sql);
}
Also, it's recommended to use prepared statements, because they prevent SQL njection attacks. More information here.
Try it this ways
for($i = 0; $i < count($name_array);$i++) {
$name_values = mysqli_real_escape_string($connection,$name_array[$i]);
$roll_values = mysqli_real_escape_string($connection,$roll_array[$i]);
$att_values = mysqli_real_escape_string($connection,$att_array[$i]);
$sql= "INSERT INTO `aclass12` (Name, RollNo, attendance) VALUES ('$name_values', '$roll_values','$att_values')";
}
Other option is to use multidimensional array with foreach.
foreach($name_array as $n_k=>$name) {
$roll = (isset($roll_array[$n_k])) ? $roll_array[$n_k] : '';
$att = (isset($att_array[$n_k])) ? $att_array[$n_k] : '';
$name = mysqli_real_escape_string($connection,$name);
$roll = mysqli_real_escape_string($connection,$roll);
$att = mysqli_real_escape_string($connection,$att);
$sql= "INSERT INTO `aclass12` (Name, RollNo, attendance) VALUES ('$name','$roll','$att')";
mysqli_query($connection,$sql);
}
I do think it would be best to use since mysql query to inject it and simply concatenate everything before that. That's something like this:
$query = "INSERT INTO tbl_name (col1, col2, col3) VALUES ";
for ($i = 0; $i < count($name_array); $i++) {
$name = mysqli_real_escape_string($conn, $name_array[$i]);
$roll = mysqli_real_escape_string($conn, $roll_array[$i]);
$att = mysqli_real_escape_string($conn, $att_array[$i]);
$query .= "('{$name}', '{$roll}', '{$att}'),";
}
$query = trim($query, ',');
$query = $query . ';';
mysqli_query($connection,$sql);
Add some damage control there (check for errors) and that's it.

Insert into table from Array PHP

I have four Array consisting of some values. I want to insert Array with same index in same row.
Eg:
$product = [Facebook, Twitter];
$sub_product = [Likes, Boost];
$plan = [10k, 20k];
$months = [3,6];
I want table to be some thing like this
+----+----------+-------------+------+--------+
| id | product | sub_product | plan | months |
+----+----------+-------------+------+--------+
| 1 | Facebook | Likes | 10k | 3 |
+----+----------+-------------+------+--------+
| 2 | Twitter | Boost | 20k | 6 |
+----+----------+-------------+------+--------+
What will be the best way to achieve this such that Index of each array falls in same row? I want to insert in HTML table
If you want to execute mysql_query in single shot then
$product = [Facebook, Twitter];
$sub_product = [Likes, Boost];
$plan = [10k, 20k];
$months = [3,6];
$query = 'insert into TABLE (product,sub_product,plan,months) values';
foreach( $product as $index => $col ){
$query .= "( '".$product[$index]."', '".$sub_product[$index]."', '".$plan[$index]."', ".$months[$index]." ),";
}
$query = rtrim( $query, ',');
mysqli_query(mysql_query);
This will be faster than executing multiple mysql_query function in a loop.
Try This Code,
foreach($product as $key=>$p){
$data = array(
'product'=>$p,
'sub_product'=>$sub_product[$key],
'plan'=>$plan[$key],
'months'=>$months[$key]
);
//Code to insert this array to Database
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
$sql = "INSERT INTO `table`('product','sub_product',...) VALUES ($data['product'],$data['sub_product'],...)";
mysqli_close($conn);
//OR If you are using Codeigniter,
$this->db->insert('table',$data);
}
this code should work,
$product = array("Facebook", "Twitter");
$sub_product = array("Likes", "Boost");
$plan = array("10k", "20k");
$months = array(3,6);
for($i=0;$i<count($product);$i++){
$product_name=$product[$i];
$sub_product_name=$sub_product[$i];
$plan_name=$plan[$i];
$month_no=$months[$i];
echo "insert into table_name (product_name, sub_product_name, plan_name, month_no) values ('$product_name', '$sub_product_name', '$plan_name', '$month_no')";
echo "<br>";
}
Thanks
Amit
Assuming all arrays have the same length and $mysqli is a connection to your database,
for ($i=0; $i < count($product); $i++) {
$query = "INSERT INTO your_table (id, product, sub_product, plan, months)";
$query .= " VALUES ('$i', '{$product[$i]}', '{$sub_product[$i]}', '{$plan[$i]}', '{$months[$i]}')";
$mysqli->query($query);
}
Assuming that the size of all the above arrays are same at a given point of time and their indexing is consistent you can use the following code:
<?php
$product = array('Facebook', 'Twitter');
$sub_product = array('Likes', 'Boost');
$plan = array('10k', '20k');
$months = array(3,6);
/* Connected to a mysql Database */
$i = 0; //initialize a counter
while($i < sizeof($product)) //Run the loop (Twice in this case)
{
//Store the current iteration value in variables
$current_product = $product[$i];
$current_sub_product = $sub_product[$i];
$current_plan = $plan[$i];
$current_months = $months[$i];
//Prepare the SQL statement
$sql = <<<EOD
INSERT INTO table_product(product,subproduct,plan,months)
VALUES ('$current_product','$current_sub_product','$current_plan',$current_months)
EOD;
$i++;
echo $sql . "<br />";
}
?>
Do on this way simple:
$count = count($product);
$index=0;
while($index<$count){
//do your stuff here i.e. insert query
$sql = "INSERT INTO your_table SET product='".$product[$index]."', sub_product='".$sub_product[$index]."', plan='".$plan[$index]."', months='".$months[$index]."' ";
mysql_query($sql);
$index++;
}

Categories