When I run the following code:
// Loop through each store and update shopping mall ID
protected function associateShmallToStore($stores, $shmall_id) {
foreach($stores as $store_id) {
$sql .= 'UPDATE my_table SET fk_shmallID = :shmall_id WHERE id = :store_id';
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':shmall_id', $shmall_id);
$stmt->bindParam(':store_id', $store_id);
$stmt->execute();
}
}
I get the following message:
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
I've also tried the following without success (without $stmt->bindParam):
$stmt->execute( array($shmall_id, $store_id));
I don't understand what I'm doing wrong.
UPDATE
I've updated my code to reflect what I actually got in my source code. There should not be any typos here.
UPDATE 2
I tried this, but I still get the same error message.
protected function associateShmallToStore($stores, $shmall_id) {
$i = 0;
$sql .= "UPDATE sl_store ";
foreach($stores as $store_id) {
$i++;
$sql .= 'SET fk_shmallID = :shmall_id, lastUpdated = NOW() WHERE id = :store_id_'.$i.',';
}
$sql = removeLastChar($sql);
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':shmall_id_'.$i, $shmall_id);
$i = 0;
foreach($stores as $store_id) {
$i++;
$stmt->bindParam(':store_id_'.$i, $store_id);
}
$stmt->execute();
}
This is the output of the SQL query:
UPDATE sl_store
SET fk_shmallID = :shmall_id, lastUpdated = NOW() WHERE id = :store_id_1,
SET fk_shmallID = :shmall_id, lastUpdated = NOW() WHERE id = :store_id_2
UPDATE 3
The code I endet up using was this:
foreach($stores as $store_id) {
$sql = "UPDATE sl_store SET fk_shmallID = :shmall_id WHERE id = :store_id";
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':shmall_id', $shmall_id);
$stmt->bindParam(':store_id', $store_id);
$res = $stmt->execute();
}
It's just as the error says, you have mixed named and positional parameters:
:name (named)
:person_id (named)
? (positional)
More than that, you have the named parameter :person_id, but you're binding to :id.
These are your parameters, I'll call them P1, P2 and P3:
UPDATE my_table SET name = :name WHERE id = :person_id ?
^ P1 ^ P2 ^ P3
And this is where you bind them:
$stmt->bindParam(':name', $name); // bound to P1 (:name)
$stmt->bindParam(':id', $person_id); // bound to nothing (no such param :id)
You probably want to bind the second parameter to :person_id, not to :id, and remove the last positional parameter (the question mark at the end of the query).
Also, each iteration through the foreach loop appends more to the query, because you're using the concatenation operator instead of the assignment operator:
$sql .= 'UPDATE my_table SET name = :name WHERE id = :person_id ?';
You probably want to remove that . before =.
For more about this, take a look at the Prepared statements and stored procedures page in the PDO manual. You will find out how to bind parameters and what the difference is between named and positional parameters.
So, to sum it up:
Replace the SQL line with:
$sql = 'UPDATE my_table SET name = :name WHERE id = :person_id';
Replace the second bindParam() call with:
$stmt->bindParam(':person_id', $person_id);
Try:
$sql = 'UPDATE my_table SET name = :name WHERE id = :id';
Related
I've created an UPDATE statement that updates only if the string's length is greater than 0.
I'm trying to escape quotes within my UPDATE statement once the condition is met. I've been using addslashes($name), but with this new condition addslashes no longer works.
Previous:
$mysqli->query("UPDATE table SET name='".addslashes($name)."' WHERE id=1") or die($mysqli->error);
Current:
$mysqli->query("UPDATE table SET name=IF(LENGTH($name)=0, name, '$name') WHERE id=1") or die($mysqli->error);
Where do I place addslashes() for this function to correctly escape characters? Will this function even work within this particular MySQL statement for PHP?
The problem with your second query is that $name inside the call to LENGTH needs to be in quotes too i.e.
$mysqli->query("UPDATE table SET name=IF(LENGTH('$name')=0, name, '$name') WHERE id=1") or die($mysqli->error);
To use addslashes in that query, you would write:
$mysqli->query("UPDATE table SET name=IF(LENGTH('".addslashes($name)."')=0, name, '".addslashes($name)."') WHERE id=1") or die($mysqli->error);
But really you should consider using a prepared statement instead; then you won't have to worry about escaping quotes. Additionally, you should check the length of $name in PHP and not run the query at all if it is empty. Something like this should work (I'm assuming you have a variable called $id which stores the id value for the update).
if (strlen($name)) {
$stmt = $mysqli->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->bind_param('si', $name, $id);
$stmt->execute() or die($stmt->error);
}
If you have multiple pieces of data to update, you could try something like this:
$name = 'fred';
$city = '';
$state = 'SA';
$id = 4;
$params = array();
foreach (array('name','city','state') as $param) {
if (strlen($$param)) $params[$param] = $$param;
}
$sql = "UPDATE table SET " . implode(' = ?, ', array_keys($params)) . " = ? WHERE id = ?";
$types = str_repeat('s', count($params)) . 'i';
$params['id'] = $id;
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
$stmt->execute() or die($stmt->error);
I've got a simple query that is not so easy to execute in PHP script:
SELECT `title` from `MY_TABLE` WHERE id in (30,32,33,44)
Usually I execute sql queries with prepared statements. I place a bunch of ? and than bind parameters. This time the numbers in parenthesis are an array of data I get from the user.
I tried this, but it does not work:
$ids = [30,32,33,44];
$stmt = $mysqli->prepare("
SELECT `title` from `MY_TABLE` WHERE id in (?)
");
// $stmt->bind_param();
$stmt->bind_param("i",$ids);
$stmt->execute();
$stmt->bind_result($title);
$stmt->store_result();
//fetch
How can I execute a set operation with prepared statements?
UPDATE:
After following your advice I came up with this
$ids = [30,32,33,44];
$questionMarks = rtrim(str_repeat('?,',count($ids)),", ");
$parameters = str_repeat('i',count($ids));
echo $questionMarks."<br>";
echo $parameters."<br>";
$stmt = $mysqli->prepare("
SELECT `title` from `MY_TABLE` WHERE id in (".$questionMarks.")
");
$scene_names = [];
$stmt->bind_param($parameters, $ids); //error here
$stmt->execute();
$stmt->bind_result($title);
$stmt->store_result();
I am still getting an error. This time it says:
Number of elements in type definition string doesn't match number of bind variables
I am not sure why it thinks that the number of elements (what is element in this case?) is wrong.
UPDATE 2:
Instead of:
$stmt->bind_param($parameters, $ids); //error here
I used:
$stmt->bind_param($parameters, ...$ids); //error gone
Taraam. Works fine.
Something like:
$ids = [30,32,33,44];
$types = array();
foreach($ids as $i){
array_push($types,'i');
}
$params = array_merge($ids,$types);
$sqlIN = str_repeat('?,',count($ids));
$sqlIN = rtrim($sqlIN, ',');
//Value of $sqlIN now looks like ?,?,?,?
$sql = "SELECT title from MY_TABLE WHERE id IN ($sqlIN)";
$stmt = $mysqli->prepare($sql);
call_user_func_array(array($stmt, 'bind_param'), $params);
$stmt->execute();
$stmt->bind_result($id);
$stmt->store_result();
SQL doesn't read the $customerID variable as a variable. I think the () is the problem because when I remove the first part of () the editor sees the variable as variable but the SQL won't work.
$customerID = $_SESSION['ID'];
$query = $conn->prepare(
"SELECT * FROM quiz_list
WHERE (
(status = 1 AND shared = 1)
OR customer = '$customerID')
AND friendly LIKE '%$searchValue%'
ORDER BY id LIMIT 25;"
);
$query->execute();
When you prepare a statement you should use placeholders for you parameters. These placeholders are then bound to the prepared statement in a second call, before executing the statement.
$query = $conn->prepare("SELECT * FROM quiz_list WHERE ((status = 1 and shared = 1) OR customer = '?') AND friendly LIKE '%?%' ORDER BY id LIMIT 25;");
$query->bind_param('is', $customerID, $searchValue);
$query->execute()
For a more elaborate example look at the mysqli prepare documentation
I have the following php mysql statment that is working fine:
if (isset($_GET['name'])) {
$data = "%".$_GET['name']."%";
$sql = 'SELECT * FROM tbl_clients WHERE fname like ?';
$stmt = $conn->prepare($sql);
$results = $stmt->execute(array($data));
$rows = $stmt->fetchAll();
$error = $stmt->errorInfo();
}
But i want to add the following so it can check to columns for the name variable:
$sql = 'SELECT * FROM tbl_clients WHERE fname like ? or lname like ?';
If i modify this statement to the above it errors out with the following:
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in /var/www/www.test.com/search.php on line 38
It's pretty obvious, you have two ? and only one item in the array you are passing to $stmt->execute
$sql = 'SELECT * FROM tbl_clients WHERE fname like :something or lname like :something';
$data = array(':something'=>'SOME VALUE');
$results = $stmt->execute($data);
In the updated query, you have two parameters, but you're only passing one value to execute. Just fix the latter problem, and it will work:
$results = $stmt->execute(array($data, $data));
I'm having trouble to convert my code from sql to mysqli. $XX can be 1 or 0. When $XX=1 I want to search for it. When $XX=0, there must be no search for $XX. Same for $YY.
Old code
$sql = "SELECT name FROM tabel WHERE 1=1";
if (!empty($XX)) {$sql .= " AND XX = 1 ";}
if (!empty($YY)) {$sql .= " AND YY = 1 ";}
When $XX=1 and $YY=1, the code will look like:
$sql = "SELECT name FROM tabel WHERE 1=1 AND XX = 1 AND YY = 1";
When $XX=0 and $YY=1, the code will look like:
$sql = "SELECT name FROM tabel WHERE 1=1 AND YY = 1";
When $XX=0 and $YY=0, the code will look like:
$sql = "SELECT name FROM tabel WHERE 1=1";
The 'problem' is that I do not want to search for XX=0 because that excludes all XX=1 answers. When XX=0, it should not search for XX.
New code
$stmt = mysqli_prepare($link, "SELECT name FROM tabel WHERE XX=? and YY=?");
mysqli_stmt_bind_param($stmt, "ii", $XX, $YY);
Who knows how the mysqli code must look like? Thanks!
EDIT
Okay, from what I get now, it should be simple. If the only possible value for XX and YY in the query is 1, you don't need bind_param.
$qry = 'SELECT name FROM table WHERE 1=1';
$qry .= (!empty($XX)) ? ' AND XX=1';
$qry .= (!empty($YY)) ? ' AND YY=1';
$stmt = mysqli_prepare($link, $qry);
And then just execute your query.
You can rewrite the query in the following way
SELECT * FROM table1 WHERE (xx = ? OR ? = 0) AND (yy = ? OR ? = 0)
Here is SQLFiddle demo
$sql = "SELECT * FROM table1 WHERE (xx = ? OR ? = 0) AND (yy = ? OR ? = 0)";
$db = new mysqli(...);
$stmt = $db->prepare($sql)) {
$stmt->bind_param('iiii', $xx, $xx, $yy, $yy);
$stmt->execute();
$stmt->bind_result(...);
another alternate if you can pass the field name as parameter
$stmt = mysqli_prepare($link, "SELECT name FROM tabel WHERE XX=? and YY=?");
mysqli_stmt_bind_param($stmt, "ii", $XX, $YY);
if you want to avoid filtering XX pass $XX as 'XX'(i.e field name) insted of 0
In such a special case when no variable is actually going into query, you can stick to your current setup. Just change prepare and bind to mysqli_query().
However, in case you need to add a variable into query, you either can use peterm's dirty solution or create the conditional query with placeholders and then call bind_param() with variable number of parameters using call_user_func_array()