Prepared statement, loop results to get more results - php

I have a query where I'm taking several results from a single table. I then need to loop through each result to get information from other tables, however, I can't get it to work.
Here's my code:
<?php
$type = 1;
if ($stmt = $cxn->prepare('SELECT username FROM users WHERE type = ?')) {
$stmt->bind_param('i', $type);
$stmt->execute();
$stmt->bind_result($username);
while ($stmt->fetch()) {
if ($stmt = $cxn->prepare('SELECT count FROM posts WHERE username = ?')) {
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->bind_result($result2);
$stmt->close();
}
}
$stmt->close();
}
?>
I get an error:
Call to a member function fetch() on a non-object
How do I fix this?

I would highly recommend a native SQL JOIN for this because it will avoid unnecessary overhead in sending potentially thousands of queries:
SELECT
u.username,
p.count
FROM
users u
LEFT JOIN // processed as LEFT OUTER JOIN so the syntax is interchangeable just fyi
posts p
ON u.username = p.username
WHERE
p.type = ?
Explaining LEFT JOIN only, we'll keep it simple =)
In the SQL above we start with username from the users table as a whole
users u just grants us the shortcut syntax for u.username so that SQL is readable and doesn't fubar
Next we want to attach the posts p table where u.username = p.username because we need the p.count for each username
Lastly we filter this conglomerate of data based on p.type being equal to something
Please note that are many things at play here depending on the DBMS. Such things include query optimizers, the exact point of filtering, etc... but that is far outside the scope of simply getting the hang of what we are trying to achieve conceptually so I will not go into detail because it will only cause confusion.

You are overwritting your stmt variable. You should use another one, like
$type = 1;
if ($stmt = $cxn->prepare('SELECT username FROM users WHERE type = ?')) {
$stmt->bind_param('i', $type);
$stmt->execute();
$stmt->bind_result($username);
while ($stmt->fetch()) {
if ($stmtCnt = $cxn->prepare('SELECT count FROM posts WHERE username = ?')) {
$stmtCnt->bind_param('s', $username);
$stmtCnt->execute();
$stmtCnt->bind_result($result2);
$stmtCnt->close();
}
}
$stmt->close();
}

Related

PHP, PDO, SQLite INNER JOIN Statement And Variable

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));

mysql prepared fetch loop, wont use connection for looped stmt

Thanks to anyone who is willing to help. I am trying to run a sql SELECT in a fetch loop of another select loop.
$mysqli = connect();
$stmt= $mysqli->prepare('SELECT lobby_id, user_penName, lobby_str
FROM `tbl_lobbies`
JOIN tbl_users ON tbl_lobbies.user_id = tbl_users.user_id
WHERE lobby_active = ?');
$stmt->bind_param('i',$on);
$stmt->execute();
$stmt->bind_result($lid, $hostName, $str);
while($stmt->fetch()){
$users=0;
$on = 1;
//echo $lid;
$stmt2= $mysqli->prepare('SELECT `user_id` FROM `tbl_usersInLobbies` WHERE lobby_id = ?');
$stmt2->bind_param('i', $lid);
echo 1;
$stmt2->execute();
$stmt2->bind_result($users);
while($stmt2->fetch()){
echo 1;
$nou .= '&nbsp<i class="fa fa-square" aria-hidden="true"></i>';
}
$stmt2->close();
This code only works if I open another connection in the loop. I know that isnt effective so im trying to see if there is another way. I know there is no variable errors in the code. I would use another form of sql in there is no other option.
PS im still a student so im sorry for any obvious answers.
Use just 1 SQL query, something like this:
SELECT tbl_lobbies.lobby_id, tbl_lobbies.user_penName, tbl_lobbies.lobby_str, tbl_usersInLobbies.user_id
FROM `tbl_lobbies`
JOIN tbl_users ON tbl_lobbies.user_id = tbl_users.user_id
LEFT JOIN `tbl_usersInLobbies` ON tbl_usersInLobbies.lobby_id = tbl_lobbies.lobby_id
WHERE lobby_active = ?

MySQL prepare statement using variable

I am using below PHP + MySQL prepare statement to select values from database, passing the variable into the statement using function, however I could not get my wanted result. The problem is I don't know how to using the variable in the prepare statement.
Question:
Could you take a look whether the syntax I am using is correct?
public function getToken($committeeValue){
$stmt = $this->conn->prepare("SELECT u.token FROM users u INNER JOIN committee c ON u.email = c.email WHERE c.'$committeeValue' = 1");
$stmt->execute();
}
Please try the below one.
public function getToken($committeeValue){
$stmt = $this->conn->prepare("SELECT u.token FROM users u INNER JOIN committee c ON u.email = c.email WHERE c.".$committeeValue." = 1");
$stmt->execute();
}
I think you are made a mistake to appending a php variable within the string.Please try this.
You made the mistake of concatenating string in PHP.
So please try this below:
public function getToken($committeeValue){
$committeeValue = trim($committeeValue);
if(!empty($committeeValue)){
$query = "SELECT u.token FROM users u INNER JOIN committee c ON u.email = c.email WHERE c.".$committeeValue." = 1";
$stmt = $this->conn->prepare($query);
$stmt->execute();
}
}
Using var content directly is not safe because it allow to inject SQL statements.
The safe way is, in your case:
public function getToken($committeeValue){
$committeeValue = trim($committeeValue);
if(!empty($committeeValue)){
$query = "SELECT u.token FROM users u INNER JOIN committee c ON u.email = c.email WHERE c.? = 1";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(1, $committeeValue);
$stmt->execute();
}
}
The query will be compiled without the var content so you dont have to worry about SQL injection.

Using two queries at the same time. PDO

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.

Multiple prepared statements (SELECT)

I'm trying to change my SQL queries with prepared statements.
The idea: I'm getting multiple records out of the database with a while loop and then some additional data from the database in the loop.
This is my old SQL code (simplified):
$qry = "SELECT postId,title,userid from post WHERE id='$id'";
$rst01 = mysqli_query($mysqli, $qry01);
// loop trough mutiple results/records
while (list($postId,$title,$userid) = mysqli_fetch_array($rst01)) {
// second query to select additional data
$query05 = "SELECT name FROM users WHERE id='$userid";
$result05 = mysqli_query($mysqli, $query05);
$row05 = mysqli_fetch_array($result05);
$name = $row05[name ];
echo "Name: ".$name;
// do more stuff
// end of while loop
}
Now I want to rewrite this with prepared statements.
My question: is it possible to run a prepared statement in the fetch of another prepared statement ? I still need the name like in the old SQL code I do for the $name.
This is what've written so far.
$stmt0 = $mysqli->stmt_init();
$stmt0->prepare("SELECT postId,title,userid from post WHERE id=?");
$stmt0->bind_param('i', $id);
$stmt0->execute();
$stmt0->bind_result($postId,$title,$userid);
// prepare second statement
$stmt1 = $mysqli->stmt_init();
$stmt1->prepare("SELECT name FROM users WHERE id= ?");
while($stmt0->fetch()) {
$stmt1->bind_param('i', $userid);
$stmt1->execute();
$res1 = $stmt1->get_result();
$row1 = $res1->fetch_assoc();
echo "Name: ".$row1['name'] ;
}
It returns an error for the second statement in the loop:
Warning: mysqli_stmt::bind_param(): invalid object or resource mysqli_stmt in ...
If I use the old method for the loop and just the prepared statement to fetch the $name it works.
You can actually do this with a single JOINed query:
SELECT p.postId, p.title, p.userid, u.name AS username
FROM post p
JOIN users u ON u.id = p.userid
WHERE p.id = ?
In general, if you are running a query in a loop, there is probably a better way of doing it.

Categories