How do I update multiple data using single query? - php

This query takes a lot of time to run when the id_array is big. How can I make it faster? Is it maybe possible to do this in one query instead of multiple updates as in my example?
<?php
$sort = 1;
$id_array = array(
56,
14,
99,
54,
8,
92
);
foreach ($id_array as $id) {
mysqli_query($conn, "UPDATE id_table SET sort = '$sort' WHERE id = '$id'");
$sort++;
}
?>

Legend has it that using a prepared statement can be quicker than other types of query when dealing with large datasets - whether this is true or not is for you to decide - but to use a prepared statement you could try like this:
$sql='update id_table set sort = ? where id = ?';
$stmt=$conn->prepare( $sql );
$stmt->bind_param( 'ii', $sort, $id );
foreach( $id_array as $index => $id ){
$sort=$index+1;
$stmt->execute();
}

assuming you have an array as
$id_array = array(56, 14, 99, 54, 8, 92);
and you db driver allow multiple sql statement
you could try using sql var a in clause and avoid loop ( avoid also quote for numeric values ) building a proper string for IN clause
$yourArray = implode(', ', $id_array);
mysqli_query($conn, " set #sort = 0;
UPDATE id_table SET sort = #sort +1 WHERE id IN ( ". $your_Array . ")");

This is my final solution. It works great and is much faster than my first attempt.
$sort = 1;
$query = "UPDATE id_table SET sort = CASE ";
foreach($id_array as $id)
{
$query = $query . "WHEN id = '$id' THEN '$sort' ";
$sort++;
}
$query = $query . "END";
mysqli_query($conn, $query);

Related

PDO: Delete query only deleting entries of first value in IN statement [duplicate]

I found this code on SO, which is great for using PDO and the IN() statement together.
$values = explode(',', $values) ; # 1,4,7
$placeholders = rtrim(str_repeat('?, ', count($values)), ', ') ;
$query = "SELECT * FROM table WHERE id IN ($placeholders)";
$stm = $db->prepare($query) ;
$stm->execute($values) ;
However, how can I mix in another addition to the query so the query looks like this:
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm = $db->prepare($query) ;
$stm->execute(array($values,$product)) ; //error happens when adding product placeholder
I thought this would work but I get:
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in line 3 (the $stm line)
Any idea how to get this to behave as intended?
UPDATED execute to array, still not working..
Solution
This should work, if $values is an array:
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm->execute(array_merge($values, array($product)));
Explanation
execute() expects one parameter - in this case an array - to be provided. By adding array_merge($values, array($product)) you create one array with $product added at the end, so the query should work correctly.
See the demo here: http://ideone.com/RcClX
$stm->execute($values,$product) ; //error happens when adding product placeholder
The problem here is that execute needs a single array. You can't pass multiple arrays, and worse, you can't nest arrays.
We already have a perfectly good $values array, so let's reuse it after you create the placeholder string.
$values = explode(',', $values) ; # 1,4,7
$placeholders = rtrim(str_repeat('?, ', count($values)), ', ') ;
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
// New!
$values[] = $product;
$stm = $db->prepare($query);
$stm->execute($values);
And an other solution can be (if you like the :param_name = $value way, as me):
$params = array(
':product' => $product
);
$_in_params = array();
foreach ( $_in_values as $idx_in => $value_in)
{
$_in_params[] = ':param_in_'.$idx_in;
$params[':param_in_'.$idx_in] = $value_in;
}
$query .= "SELECT * FROM table WHERE id IN (".join(',',$_in_params).") AND product=:product";
I'm not sure if this is the best and the most optimal solution, but it's a little bit more human readable :) And it can be helpful if you have a big an complicated query and you want to debug it
(I'm curious if someone have a good argument why NOT to do in this way)
You forgot to prepare it ^_^
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm = $db->prepare($query) ;
$stm->execute($values,$product) ; //p00f
And aside from that execute() should only have one parameter
So the above won't work AT ALL!
See the DOCs
Placeholders version if you need it
$values = [1, 4, 7, 8];
$placeholders = preg_filter('/^/', ':prefix_', array_keys($values)));
$query = 'SELECT * FROM table WHERE id IN ( '. implode(', ', $placeholders) . ')';
$stmt = $db->prepare($query);
if (count($values) > 0) {
foreach ($values as $key => $current_value) {
$stmt->bindValue($placeholders[$key] , $current_value, PDO::PARAM_STR);
}
}
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

Datatables - Filter SQL results in server-side

I'm trying to create a filter in DataTables, but what I found is only filtering the data in "front end" (in the datatables script). I have 10K rows in the SQL table so I think, the "front end filtering/searching" is not my best option. I need to create a filter to my SQL Query in server-side, and get back only the filtered rows (datas).
Also the search option is not good option for me because I have in tables values like 1 or 2 (boolean).
My DataTables using this method (way) of fetching datas from SQL in backend:
include 'config.php';
## Read value
$draw = $_POST['draw'];
$row = $_POST['start'];
$rowperpage = $_POST['length']; // Rows display per page
$columnIndex = $_POST['order'][0]['column']; // Column index
$columnName = $_POST['columns'][$columnIndex]['data']; // Column name
$columnSortOrder = $_POST['order'][0]['dir']; // asc or desc
$searchValue = $_POST['search']['value']; // Search value
$searchArray = array();
## Search
$searchQuery = " ";
if($searchValue != ''){
$searchQuery = " AND (emp_name LIKE :emp_name or
email LIKE :email OR
city LIKE :city ) ";
$searchArray = array(
'emp_name'=>"%$searchValue%",
'email'=>"%$searchValue%",
'city'=>"%$searchValue%"
);
}
## Total number of records without filtering
$stmt = $conn->prepare("SELECT COUNT(*) AS allcount FROM employee ");
$stmt->execute();
$records = $stmt->fetch();
$totalRecords = $records['allcount'];
## Total number of records with filtering
$stmt = $conn->prepare("SELECT COUNT(*) AS allcount FROM employee WHERE 1 ".$searchQuery);
$stmt->execute($searchArray);
$records = $stmt->fetch();
$totalRecordwithFilter = $records['allcount'];
## Fetch records
$stmt = $conn->prepare("SELECT * FROM employee WHERE 1 ".$searchQuery." ORDER BY ".$columnName." ".$columnSortOrder." LIMIT :limit,:offset");
// Bind values
foreach($searchArray as $key=>$search){
$stmt->bindValue(':'.$key, $search,PDO::PARAM_STR);
}
$stmt->bindValue(':limit', (int)$row, PDO::PARAM_INT);
$stmt->bindValue(':offset', (int)$rowperpage, PDO::PARAM_INT);
$stmt->execute();
$empRecords = $stmt->fetchAll();
$data = array();
foreach($empRecords as $row){
$data[] = array(
"emp_name"=>$row['emp_name'],
"email"=>$row['email'],
"gender"=>$row['gender'],
"salary"=>$row['salary'],
"city"=>$row['city']
);
}
## Response
$response = array(
"draw" => intval($draw),
"iTotalRecords" => $totalRecords,
"iTotalDisplayRecords" => $totalRecordwithFilter,
"aaData" => $data
);
echo json_encode($response);
In this code as you can see I have Search option, but as I said I can't use it for filtering columns with boolean values for example.
Another example what I want to do:
I have a column named by "edited" with boolean values.
How can I get those rows where the column "edited" have values 0?
I'm using MariaDB.
Thank you for your help!
You can easy write ...WHERE edited = :edited ... the value of edited should be 0 for false and 1 for true.
So in your example:
## Search
$searchQuery = " ";
if($searchValue != ''){
$searchQuery = " AND (emp_name LIKE :emp_name or
email LIKE :email OR
city LIKE :city ) AND
edited = :edited";
$searchArray = array(
'emp_name'=>"%$searchValue%",
'email'=>"%$searchValue%",
'city'=>"%$searchValue%",
'edited'=>$edited
);
}

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;

What is the correct way of printing results set by `SELECT *` with multiple `WHERE` clauses in prepared statements using `fetch_assoc()` in PHP-MYSQL?

My query is below:
$query = 'SELECT * FROM `table_name` WHERE `uid` = ? AND `email` = ?';
$stmt_select = $conn->prepare($query);
$stmt_select->bind_param('is', $user_id, $user_email);
$user_id = $_SESSION['uid'];
$user_email = $_SESSION['user_email'];
$result = $stmt_select->execute();
I want to print results set using fetch_assoc, this is because I don't want to bind_result() to all 23 columns' name, I want to print it using $row['column_name'], what is the correct way of achieving it?
If you want to see my code, I asked another question here:
How to SELECT * with multiple WHERE using fetch_assoc in prepared statements in PHP-MYSQL?
But it didn't get answered correctly, so instead of correcting my code, can you tell me what's the best way to achieve it?
I had the same issue using SELECT * in mysqli. The issue lies with the bind_result part. Normally you would need to add many variables. Meaning if you had about 20 columns, you would need 20 variables to include in the bind_result statement.
I've tailored my solution to fix your issues.
$query = 'SELECT * FROM `table_name` WHERE `uid` = ? AND `email` = ?';
$stmt_select = $conn->prepare($query);
$stmt_select->bind_param('is', $user_id, $user_email);
$user_id = $_SESSION['uid'];
$user_email = $_SESSION['user_email'];
$result = $stmt_select->execute();
$stmt_select->store_result();//after this line we can output the number of rows if you need to check that as well
$number_of_rows = $stmt_select->num_rows;
$meta = $stmt_select ->result_metadata();
$parameters = array();
$results = array();
while ($field = $meta->fetch_field()) {
$parameters[] = &$row[$field->name];
}
call_user_func_array(array($stmt_select , 'bind_result'), $parameters);
while ($stmt_select ->fetch()) {
foreach ($row as $key => $val) {
$x[$key] = $val; //here we get the key => value (Column => Value)
}
$results[] = $x; //lets grab everything here
}
print_r($results);

How do I update mysql database WHERE value = value from PHP array?

I am trying to use the keys of an array as values to update a column in my database. The column in question is the sort order for the rows.
Lets say the sort column values for each row are 1, 3, 5, 8, 9, 10, 12.
When the code is executed this is to be updated to read 1, 2, 3, 4, 5, 6, 7.
My code below does what I am trying to achieve when I echo the values however I am having a problem with the update query.
$sql = "SELECT asset, sort FROM portfolio ORDER BY sort ASC";
$query = mysqli_query($conn, $sql);
$i = 0;
while ($row = mysqli_fetch_assoc($query)){
$asset[$i] = $row['asset'];
$sort[$i] = $row['sort'];
$new_sort = $i+1;
$assets = implode(',', $asset);
$update_sql = "UPDATE portfolio SET sort='$new_sort' WHERE asset IN ('$assets')";
mysqli_query($conn, $update_sql);
$i++;
}
Using the following only the first row is being updated:
$assets = implode(',', $asset);
Using the following all rows are being updated, however they are all being set to the last value, in this example it would be 7.
$assets = join("','",$asset);
UPDATE: $assets is a string, an example would be google,yahoo,apple etc..
Any ideas where I am going wrong?
Many Thanks.
You are setting the new_sort for every asset every time you loop through.
First loop:
$assets[0] => "asset1"
$new_sort => 2
Update new_sort = 2 where asset in $assets. (So only asset1 will be updated.)
Second loop:
$assets[0] => "asset1"
[1] => "asset2"
$new_sort => 3
Update new_sort = 3 where asset in $assets (So asset1 and asset 2 will be updated)
This will result into always setting the new_sort for every asset to the latest new_sort value;
The code for your output could be:
while ($row = mysqli_fetch_assoc($query)){
$new_sort = $i+1;
$update_sql = "UPDATE portfolio SET sort='" . $new_sort . "' WHERE asset='" . $row['asset'] . "';";
mysqli_query($conn, $update_sql);
$i++;
}
This the solution for your desired output.
$sql = "SELECT asset, sort FROM portfolio ORDER BY sort ASC";
$query = mysqli_query($conn, $sql);
$i = 0;
while ($row = mysqli_fetch_assoc($query)){
$asset[$i] = $row['asset'];
$sort[$i] = $row['sort'];
$new_sort = $i+1;
$assets = implode(',', $asset);
$update_sql = "UPDATE portfolio SET sort='$new_sort' WHERE asset like '".$row['asset']."'";
mysqli_query($conn, $update_sql);
$i++;
}
First of all you need to move your UPDATE query outside the while loop than you can use like that:
$assets = implode("','", $asset); // split $asset in comma and single quote.
$update_sql = "UPDATE portfolio SET sort='$new_sort' WHERE asset IN ('$assets')";
You are already store your values in an array $asset[$i] = $row['asset']; so no need to use query inside the while loop.
In your code, you are update the last value of $i in sort column.
The other solution is very simple, update single record as:
<?php
$sql = "SELECT asset, sort FROM portfolio ORDER BY sort ASC";
$query = mysqli_query($conn, $sql);
$i = 0;
while ($row = mysqli_fetch_assoc($query)){
$new_sort = $i+1;
$assets = $row['asset'];
$update_sql = "UPDATE portfolio SET sort = '$new_sort' WHERE asset = '$assets'";
mysqli_query($conn, $update_sql);
$i++;
}
?>

Categories