I am trying to do a multi query using prepared statements.
I am getting number of bind param errors :
Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in C:\wamp\www\c\index.php on line 35
Line 35 is:
$stmt->bind_param('i', $user_id);
Here is total codes:
I tried several examples but couldnt make it work.
Example 1:
$stmt->bind_param('i', $id); //output id from session
Example 2:
$stmt->bind_param('ii',$id, $user_id);
And some more tries too.
$id = $_SESSION['id']; // value comes from session and its full
$stmt = $mysqli->prepare("SELECT users.*, stores.*, products.* FROM stores, products, users WHERE users.id = ? AND stores.user_id = ? AND products.user_id = ?");
$stmt->bind_param('i', $user_id);
$stmt->execute();
$stmt->bind_result($id, $user_id, $pname);
$stmt->fetch();
$stmt->close();
echo $pname;
When I do queries in phpmyadmin codes works fine on $sql as following 2 queries:
$sql = "SELECT users.*, stores.*, products.*\n"
. "FROM stores, products, users\n"
. "WHERE ((users.id) AND (stores.user_id) AND (products.user_id))";
AND without php code
SELECT users.*, stores.*, products.*
FROM stores, products, users
WHERE ((users.id)
AND (stores.user_id)
AND (products.user_id))
This is the closest example :
I am having error:
Warning: mysqli_stmt::bind_result(): Number of bind variables doesn't match number of fields in prepared statement in C:\wamp\www\c\index.php on line 37
Line 37 is :
$stmt->bind_result($user_id, $username, $pname);
$id = $_SESSION['id'];
Closest code :
$stmt = $mysqli->prepare("SELECT users.*, stores.*, products.* FROM stores, products, users WHERE users.id = stores.user_id AND stores.user_id = products.user_id AND products.user_id = ?");
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->bind_result($user_id, $username, $pname);
$stmt->fetch();
$stmt->close();
echo $pname;
Your prepared statement contains 3 questionmarks/placeholder. So you have to bind exactly 3 values.
I think this should work:
$stmt = $mysqli->prepare("SELECT users.*, stores.*, products.* FROM stores, products, users WHERE users.id = ? AND stores.user_id = ? AND products.user_id = ?");
$stmt->bind_param('iii', $user_id, $user_id, $user_id);
See examples at: http://php.net/manual/de/mysqli-stmt.bind-param.php
Here is working sample of the code, I had to change:
SELECT users.*, stores.*, products.* FROM
To
SELECT users.id, users.username, stores.user_id, stores.name, products.user_id, products.pname FROM
And rest of the code like so: and its working now, I wouldlike to know if its safe to use on a live and dynamic website ?
Can someone correct the code please.
Here is total working code
$id = $_SESSION['UserId'];
$stmt = $mysqli->prepare("SELECT users.id, users.username, stores.user_id, stores.name, products.user_id, products.pname
FROM stores, products, users
WHERE users.id = ?
AND stores.user_id = users.id
AND products.user_id = users.id");
$stmt->bind_param('i', $id);
$stmt->execute();
$stmt->bind_result($id, $username, $user_id, $name, $user_id, $pname);
$stmt->fetch();
$stmt->close();
echo $pname;
echo"<br>" .$name;
echo "<br>".$username;
I tried INNER JOIN AND LEFT JOIN (Mentioned in comment) but couldnt made both. work
EDİT :
Same query with INNER JOIN its working.
$sid = $_SESSION['UserId'];
$stmt = $mysqli->prepare("SELECT u.id, u.username, s.user_id, s.name, p.user_id, p.pname FROM stores AS s INNER JOIN products AS p ON p.store_id = s.store_id INNER JOIN users AS u ON u.id = p.user_id WHERE s.user_id = ?");
$stmt->bind_param('i', $sid);
$stmt->execute();
$stmt->bind_result($id, $username, $user_id, $name, $user_id, $pname);
$stmt->fetch();
$stmt->close();
echo $pname;
echo"<br>" .$name;
echo "<br>".$username;
Related
I need to do a PHP PDO call to my db with an INNER JOIN and WHERE clause.
In navicat GUI this statement is running fine and i can see the results. The problem come out lather in php environment about string concatenation.
I would like to format this request so that it can be digested by php:
SELECT * FROM tsourcetb as T INNER JOIN users as U ON U.username = T.username WHERE U.username = $username AND T.username = $username;
what I tried to do
$sth = $db->prepare("SELECT * FROM tsourcetb as T INNER JOIN users as U ON U.username = T.username WHERE U.username = $username AND T.username = $username");
the return is an error indicating that there is no table with the variable name. Basically it takes the variable as the name of the table the return is an error indicating that there is no table with the variable name. Basically it takes the variable as the table name and not the table name as it should like (SELECT * FROM $username) jumping out the first part of statement).
The intent is to have all the records of table A where the username field is = to the username field of table B with value passed from a variable.
Thank for any suggestion to achieve my goal.
UPDATE
php is magic need to try and retray. At the end tish one help me to goal:
$username = ($_POST['username']);
$password = ($_POST['password']);
$statement = $db->prepare('SELECT p.* FROM `tsourcetb` as p LEFT JOIN `users`as s ON p.username = s.username WHERE s.username = :username;');
$statement->bindParam(':username', $username, PDO::PARAM_STR);
$statement->execute();
/* look here -> $statement->fetchall(PDO::FETCH_ASSOC) */
$array_select = $statement->fetchall(PDO::FETCH_ASSOC);
echo json_encode($array_select, JSON_PRETTY_PRINT);
<?php
$sth = $db->prepare("SELECT * FROM `tsourcetb` as T INNER JOIN users as U ON U.username = T.username WHERE U.username = ? AND T.username = ? ");
$sth->execute([$username,$username]);
$results = $sth->fetchall();
?>
wrapper your table name with backticks and also use placeholders
Try this:
$stmt = $db->prepare("SELECT * FROM tsourcetb as T INNER JOIN users as U ON U.username = T.username WHERE U.username = :username AND T.username = :username");
$stmt->bindValue(':username', $username, PDO::PARAM_STR);
$stmt->execute();
You need to bind a value with prepared statement:
Source: Docs
You have to bind parameters when you are making an dynamic query with PDO.
Change this in your query.
$username -> :username
And before you make the call
$yourQueryObj->bindValue(':username', $username, PDO::PARAM_STR);
That's why prepared statments are safer than regular variables as you assign it's type before it's sent for query.
You can read about it here
http://php.net/manual/en/pdostatement.bindvalue.php
You should be able also execute with array of parameters after preparing like that :
$sth = execute(array(':username'=> $username));
I have simple prepared statement, and i can't find solution to bind list of id's, so as you can see in first statement i get all ids that i need, and in next statement i need to put all those ids into IN clause, but i'm not able to do it, any suggestions how and what is best way to do it ?
$stmt = $mysqli->prepare("SELECT id FROM user WHERE groupId = ? ORDER BY id LIMIT ? OFFSET ?");
$stmt->bind_param("iii", $args['groupId'], $pageSize, $offset);
$stmt->execute();
$stmt->bind_result($id);
$userIds= array();
while ($stmt->fetch()) {
$userIds[] = $id;
}
$stmt= $mysqli->prepare("SELECT a.id as attendantId, a.firstName, a.lastName, c.id as caringId, c.startDate, c.endDate FROM attendant a LEFT JOIN caring c ON c.attendantId = a.id WHERE a.id IN (?)");
$stmt->bind_param('i', $userIds);
$stmt->bind_param('i', implode(',', $userIds));
This is my code. I execute then nothing happen. Pls check my code
$id = trim(htmlentities($_REQUEST['id'],ENT_QUOTES)); //call the action from previous page
//fetch data
$stmt = $dbi->prepare("SELECT a.telco, a.no_siri, a.no_topup, a.amount, a.requestingAgentID, a.requestDateTime, a.isUsed, b.name FROM card_telco a LEFT JOIN agents b ON a.requestingAgentID = b.id WHERE id = ?"); //query
$stmt->bind_param('s', $id); //binding
mysqli_stmt_execute($stmt); //execute
mysqli_stmt_store_result($stmt); //store the result
$count = mysqli_stmt_num_rows($stmt); //execute rows
$stmt->bind_result($newTelco, $noSiri, $noTopup, $newAmount, $newRequestAgentID, $newRequestDateTime, $isUsing, $newName, $agendId); //binding new result
$stmt->execute() or die(mysqli_error()); //execute the statement
$stmt->store_result() //store new result
$stmt->fetch(); //fetch the data
$stmt->close(); //close the statement
ChromePhp::log('here'); //console
ChromePhp::log($newTelco, $noSiri); //console
Okay i got it!! My query is wrong.
SELECT a.id, a.telco, a.no_siri, a.no_topup, a.amount, a.requestingAgentID, a.requestDateTime, a.isUsed, b.name FROM card_telco a LEFT JOIN agents b ON a.requestingAgentID = b.id WHERE a.id = ?
This is my new query. Thanks for helping me
The array showcasef holds 20 items per page. I do 3 different queries within the foreach loop, which is 60 queries (just for the loop, there's additional queries too).
<?php
foreach($showcasef as $itemf){
$sf_id = $itemf['sf_id'];
$sf_url = $itemf['sf_url'];
$sf_title = $itemf['sf_title'];
$sf_urltitle = post_slug($sf_title);
// Fetch number of favs
$stmt = $conn->prepare("SELECT COUNT(f_id) FROM favourites WHERE f_showcaseid=?");
$stmt->bind_param("i", $sf_id);
$stmt->execute();
$stmt->bind_result($numfFavs);
$stmt->fetch();
$stmt->close();
// Fetch class
$stmt = $conn->prepare("SELECT avg(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt->bind_param("i", $sf_id);
$stmt->execute();
$stmt->bind_result($sf_class);
$stmt->fetch();
$stmt->close();
// Fetch number of classes
$stmt = $conn->prepare("SELECT COUNT(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt->bind_param("i", $sf_id);
$stmt->execute();
$stmt->bind_result($numfClasses);
$stmt->fetch();
$stmt->close();
?>
Render HTML here
<?php } ?>
Will this be a severe performance issue, or are these particular queries relatively simple? If I keep the columns indexed, should it perform okay with millions of rows (potentially)? Or can the queries be optimized/simplified?
Here's how I get the showcasef:
$stmt = $conn->prepare("SELECT s_id,s_url,s_title FROM showcase WHERE s_userid=? ORDER BY s_date DESC LIMIT $skippingFactor, 20");
$stmt->bind_param("i", $u_id);
$stmt->execute();
$stmt->bind_result($sf_id,$sf_url,$sf_title);
while($stmt->fetch())
{
$showcasef[] = [
'sf_id' => $sf_id,
'sf_url' => $sf_url,
'sf_title' => $sf_title
];
}
$stmt->close();
A few suggestions here.
Reuse prepared statements
You are creating three prepared statements inside the loop. Why don't you create your statements only once, and then reuse them using multiple binds?
<?php
$stmt1 = $conn->prepare("SELECT COUNT(f_id) FROM favourites WHERE f_showcaseid=?");
$stmt1->bind_param("i", $sf_id);
$stmt1->bind_result($numfFavs);
$stmt2 = $conn->prepare("SELECT avg(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt2->bind_param("i", $sf_id);
$stmt2->bind_result($sf_class);
$stmt3 = $conn->prepare("SELECT COUNT(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt3->bind_param("i", $sf_id);
$stmt3->bind_result($numfClasses);
foreach($showcasef as $itemf) {
$sf_id = ...
$stmt1->execute();
$stmt1->fetch();
/* if the fetch succeedes then $numfFavs will contain the count */
$stmt2->execute();
...
$stmt3->execute();
..
}
$stmt1->close();
$stmt2->close();
$stmt3->close();
Use a single query to Count the rows and calculate the average
You can combine the second and third statement a single SQL query:
SELECT COUNT(r_class) AS cnt, AVG(r_class) AS average
FROM ranks
WHERE r_showcaseid=?
Use a single query instead a foreach loop
With the previous suggestions you can get better performances. But are you really sure you need a foreach loop?
If your IDs are returned by another query, instead of a foreach loop is better to use a subquery:
SELECT f_showcaseid, COUNT(f_id)
FROM favourites
WHERE f_showcaseid IN (SELECT id FROM ... WHERE ...)
GROUP BY f_showcaseid
or you can provide a list of IDs to the query:
SELECT f_showcaseid, COUNT(f_id)
FROM favourites
WHERE f_showcaseid IN (?,?,?,?,?)
GROUP BY f_showcaseid
(you can dynamically create the list of ? if the number of IDs is not fixed)
You could do this in a single query I think.
Something like the following:-
SELECT f_showcaseid, COUNT(f_id), avg(r_class), COUNT(r_class)
FROM ranks WHERE r_showcaseid IN (".implode(',', $showcasef).")
GROUP BY f_showcaseid
Of course, to use parameters you would need to do that a bit more elegantly:-
<?php
$stmt = $conn->prepare("SELECT f_showcaseid, COUNT(f_id), avg(r_class), COUNT(r_class)
FROM ranks WHERE r_showcaseid IN (".implode(',', str_split(str_repeat('?', count($showcasef)), 1)).")
GROUP BY f_showcaseid");
foreach($showcasef as $itemf)
{
$stmt->bind_param("i", $itemf['sf_id']);
}
$stmt->execute();
$stmt->bind_result($numfClasses);
$stmt->fetch();
$stmt->close();
?>
Okay so, I don't really know anything about PDO, my friend just asked me to post this here since he's not very good at English. Anyway, this is how he explained it to me:
The code provided is supposed to get a couple of values, save them, and it's supposed to get something out of another table with the help of the values gotten from earlier. The problem according to my friend is that it doesn't get the second value.
Code:
$user_email = $_SESSION['user_email'];
$query = $db->prepare("SELECT username,id,password FROM user WHERE email=:email");
$query->bindParam(':email', $user_email, PDO::PARAM_INT);
$query->execute();
$row = $query->fetch();
$user_username=$row['username'];
$user_group=$row['group'];
$query_group = $db->prepare("SELECT color,name FROM group WHERE id=:id");
$query_group->bindParam(':id', $user_group, PDO::PARAM_INT);
$query_group->execute();
$row = $query_group->fetch();
$group_color=$row['color'];
$group_name=$row['name'];
The word group used as a table name needs to be enclosed in backticks. group is a reserved key word (GROUP BY clause).
SELECT
color,
name
FROM `group`
WHERE id = :id
Using the above would work.
You can shorten the entire code by using a JOIN clause too. As commented above by Prix, the code shall be:
$user_email = $_SESSION['user_email'];
$query = $db->prepare("SELECT
u.username,
u.id,
u.password,
g.color,
g.name
FROM user u
JOIN `group` g
ON g.id = u.id
WHERE u.email = :email");
// I think emails are supposed to be `PDO::PARAM_STR`
$query->bindParam(':email', $user_email, PDO::PARAM_INT);
$query->execute();
$row = $query->fetch();
$user_username = $row['username'];
$group_color = $row['color'];
$group_name = $row['name'];
You don't have group in your select statement .
If you don't use * in your select you must have the field name in your query .
$query = $db->prepare("SELECT username,id,password FROM user WHERE email=:email");
This query gives you only username,id,password back NOT the field group .
so try to use $row['group'] is wrong .
$user_group=$row['group'];
So also put group in your select statement
Place also group in backticks it's a reserved word
$query = $db->prepare("SELECT id, username, password, `group` FROM user WHERE email=:email");
This is also a reason for important variables (e.g for next query) to consider their validity.
if (isset($row['group'])) {
database logic
} else {
error
}
With this simple test you would have found the error itself.