I am trying to get a list of sites ids according to a user id.
This is what I've got so far.
public function getSites() {
$stmt = $this->db->prepare("SELECT Sites_idSites FROM favorites WHERE User_idUser=:idUser");
$userId = $_SESSION['user_session']['idUser'];
$stmt->bindparam(":idUser", $userId);
$stmt->execute();
$siteList = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($siteList as $value) {
foreach($value as $key) {
$stmt = $this->db->prepare("SELECT * FROM sites WHERE idSites=:siteList");
$stmt->bindparam(":siteList", $key);
}
$stmt->execute();
$userSites = $stmt->fetch(PDO::FETCH_ASSOC);
}
return $userSites;
This is the part that I go to "favorites" table and get all the site's ids that correspond to the user id.
$stmt = $this->db->prepare("SELECT Sites_idSites FROM favorites WHERE User_idUser=:idUser");
$userId = $_SESSION['user_session']['idUser'];
$stmt->bindparam(":idUser", $userId);
$stmt->execute();
$siteList = $stmt->fetchAll(PDO::FETCH_ASSOC);
$siteList return as an array like this:
Array
(
[0] => Array
(
[Sites_idSites] => 20
)
[1] => Array
(
[Sites_idSites] => 21
)
[2] => Array
(
[Sites_idSites] => 22
)
)
Now, I want to go to the table where all the sites are and only get the ones with those ids.
This is what I am using, but it only gets the last one:
foreach($siteList as $value) {
foreach($value as $key) {
$stmt = $this->db->prepare("SELECT * FROM sites WHERE idSites=:siteList");
$stmt->bindparam(":siteList", $key);
}
$stmt->execute();
$userSites = $stmt->fetch(PDO::FETCH_ASSOC);
}
If I do print_r($userSites), I will return:
Array
(
[idSites] => 22
[name] => rwrwer
[url] => werwerwerwer
[Category_idCategory] => 1
)
As you can see, it is only returning the last one. How do I make it return an array with all the sites in it? Am I doing something wrong?
I finally fixed it:
public function getSites() {
$stmt = $this->db->prepare("SELECT sites.* FROM favorites INNER JOIN sites ON favorites.Sites_idSites = sites.idSites WHERE favorites.User_idUser = :idUser");
$userId = $_SESSION['user_session']['idUser'];
$stmt->bindparam(":idUser", $userId);
$stmt->execute();
$siteList = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $siteList;
}
This is because you are running the query outside of the inner loop where you bind the values.
foreach($siteList as $value){
foreach($value as $key){
$stmt = $this->db->prepare("SELECT * FROM sites WHERE idSites=:siteList");
$stmt->bindparam(":siteList",$key);
// Bind and rebind, so only the last one "Sticks"
}
// Run the query after the loop
$stmt->execute();
$userSites = $stmt->fetch(PDO::FETCH_ASSOC);
}
You are basically rebinding the :siteList on each iteration. Then when you run it, only the last time you bound it "sticks". Also fetch will only return a single row (at least without looping over it).
You could just move that inside of the loop and then do fetchAll, but a better way is to build a list and then use IN() like this:
foreach($siteList as $value){
$i = 0;
$ids = [];
$where = [];
$sql = 'SELECT * FROM sites WHERE';
foreach($value as $key){
$placeholder = ":id_{$i}";
$where[] = $placeholder;
$ids[$placeholder] = $key;
++$i;
}
$this->db->prepare($sql . ' idSites IN( ' . implode(',', $where) . ' )');
$stmt->execute($ids);
$userSites = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
The SQL should look like this:
SELECT * FROM sites WHERE idSites IN( :id_1,:id_2,:id_3 )
And the $ids array should look like this
$ids = [':id_1'=>1,':id_2'=>53,':id_3'=>1239];
Except, I just made up those numbers (obviously).
This way, you can reduce the number of queries you execute. You may even be able to put it outside of the loop(s) entirely, but without more context I can't really say that. The basic thing is, is that calling the database is expensive and you should endeavor to do so as few times as possible.
Related
I am working out a function that is meant to query to the database using PDO. I am working with arrays to execute. I am getting error HY093. Below is my code
//my function
function test_function($statement,$data,$connect)
{
$gg = implode(',',$data);
$sth = $connect->prepare($statement);
$sth ->execute(array($gg));
$r_result = $sth->fetch();
$show_result = $r_result['0'];
return $show_result;
}
$datas = array("':ids' => 1"," ':stats' => 1");
$showsh = test_function("SELECT COUNT(*) FROM table WHERE col1 > :ids AND col2 =
:stats",$datas,$con);
echo $showsh;
Any guidance will be helpful.
Your first error is in the creation of the array. You're creating an array with 2 strings, instead of an array with 2 key/value pairs. It should be this:
$datas = array(':ids' => 1,':stats' => 1);
Next up is inside of the function. You're turning the $data variable into a string, then passing that inside of an array into your query. Forget all that, and just pass $data into your execute.
$sth = $connect->prepare($statement);
$sth ->execute($data);
Refactor $datas to [":ids" => 1, ":stats" => 1]
Then edit the function:
function test_function($statement,$data,$connect)
{
$sth = $connect->prepare($statement);
$sth ->execute($data);
$r_result = $sth->fetch();
$show_result = $r_result['0'];
return $show_result;
}
If you must not change the $datas format, you must refactor it within the code. Something like:
$correctData = [];
foreach ($datas as $item) {
$elements = explode("=>", $item);
$key = preg_replace("/\s\'/", "", $elements[0]);
$element = preg_replace("/\s\'/", "", $elements[1]);
$correctData[] = [$key => $element];
}
$showsh = test_function("SELECT COUNT(*) FROM table WHERE col1 > :ids AND col2 =
:stats",$correctData,$con);
Edited: preg_replace("(/\s)(\')/", "",... to preg_replace("/\s\'/", "",...
Thank you Aynber for your answer. I am posting an answer using the ? instead of the :. In this answer I am not using the associative array.
function test_function($statement,$data,$connect)
{
$sth = $connect->prepare($statement);
$sth ->execute($data);
$r_result = $sth->fetch();
$show_result = $r_result['0'];
return $show_result;
}
$datas = array(1,1);
$showsh = test_function("SELECT COUNT(*) FROM table WHERE col1 >? AND col2 = ?",$datas,$con);
echo $showsh;
So currently I am having some issues with trying to access an element in this multidimensional array. So what I am trying to do is to create 3 different arrays of different classes, and then return them in array at the end.
The problem comes when I am trying to accsess one of the array's in the $result array. I have checked and there are elements in the array's but I am unable to access them.
public function search($searchString) : array
{
$bloggArr[] = array();
$bloggerArr[] = array();
$innleggArr[] = array();
$stmt = $this->db->prepare("SELECT * FROM blogg WHERE
bnavn=:bnavn");
$stmt->bindParam('bnavn', $searchString, PDO::PARAM_STR);
$stmt->execute();
while ($blogg=$stmt->fetchObject("Blogg"))
{
$bloggArr[]=array('blogg'=>$blogg);
echo $bloggArr['blogg']->hentBnavn();
// sort($bloggArr);
}
$stmt = $this->db->prepare("SELECT * FROM blogger WHERE
fornavn=:fornavn OR etternavn=:etternavn");
$stmt->bindParam('fornavn', $searchString, PDO::PARAM_STR);
$stmt->bindParam('etternavn', $searchString, PDO::PARAM_STR);
$stmt->execute();
while ($blogger = $stmt->fetchObject("Blogger"))
{
$bloggerArr[]= array('blogger' => $blogger);
// sort($bloggArr);
}
$stmt = $this->db->prepare("SELECT * FROM innlegg WHERE tittel=:tittel");
$stmt->bindParam('tittel', $searchString, PDO::PARAM_STR);
$stmt->execute();
while ($innlegg = $stmt->fetchObject("Innlegg"))
{
$innleggArr[] = array('innlegg' => $innlegg);
// sort($innleggArr);
}
$result = array('bloggArr' => $bloggArr, 'bloggerArr' =>
$bloggerArr, 'innleggArr' => $innleggArr);
return $result;
}
I thought I would be able to access the element in the second array by:
echo $resultat['bloggArr']['blogg']->SomeFunction();
the problem is that I get the error message that ['blogg'] is Undefined index. I am been unable to find a way to access the second array elements for a while now, and are wondering if anyone could point me in the right direction. Thanks for all help.
You're not using your arrays properly. Just considering $bloggArr:
$bloggArr[] = array();
creates this:
Array
(
[0] => Array
(
)
)
that line should be changed to:
$bloggArr = array();
To create an empty array. Then, each time through the loop,
$bloggArr[]=array('blogg'=>$blogg);
adds an element like this:
[1] => Array
(
[blogg] => <your object>
)
So, to access those values in the $result array you would need to use a loop:
foreach ($result['bloggArr'] as $blogg) {
echo $blogg['blogg']->SomeFunction();
}
If your queries will only return one result, then you could simply change this line:
$bloggArr[]=array('blogg'=>$blogg);
to
$bloggArr=array('blogg'=>$blogg);
and then you could access the function via
echo $result['bloggArr']['blogg']->SomeFunction();
What's the best way to run SQL query for each item in an array?
I've got the $array of codes:
Array
(
[0] => 12345
[1] => 12346
[3] => 12347
)
Now I'd like to run the following SQL query for each item in the $array:
SELECT * FROM `TABLE` a WHERE a.`Code` = :code
PHP I've been using:
$results = array();
$statement = $pdo->prepare($sql);
$statement->bindParam(':code', $value);
foreach ($array as $key => $value) {
$statement->execute();
while (($results = $statement->fetch(PDO::FETCH_ASSOC)) !== false) {
echo $results;
}
}
Rather than running multiple queries, you could run one query and then loop over the results:
SELECT * FROM `TABLE` a WHERE a.`Code` IN (:codes);
Which would be something along these lines in your PHP:
$question_marks = str_repeat("?,", count($array_of_codes)-1) . "?";
$statement = $pdo->prepare($sql);
$statement->bindParam(:codes, $question_marks);
$statement->execute($array_of_codes);
while (($results = $statement->fetch(PDO::FETCH_ASSOC)) !== FALSE) {
echo $results;
}
Where $array_of_codes is your PHP array containing the Code parameter for each result you want to look up.
Credit where it's due This question helped with how to do WHERE...IN queries with PDO.
Having trouble getting all match results for a particular session ID. I want to not include the session ID but include all other results for now (then will add conditions in php). I am just getting the rows for one ID (128). So if the session ID is 125, it excludes this but only picks up 128 which is first in the records but after three 128 entries (for three questions) is an ID 127 that does not get included. When printing the count it tells me 3, there should be 6. So I assume the problem is within the function.
Any ideas how to push this through? Here's my function:
function quiz_match($user_id, $question_id ,$choice_id){
$query = mysqli_query($_POST['x'], "SELECT * FROM `question_answers` WHERE `user_id` <> $user_id AND `question_id` = $question_id AND `choice_id` = $choice_id" );
while($row = mysqli_fetch_assoc($query)){
$rows[] = $row;
if (count($rows)>0){
foreach ($rows as $key => $value) {
$u_id = $value['user_id'];
$array_q= [];
array_push($array_q, $u_id, $value['question_id'], $value['choice_id']);
//$result = count($array_q);
//echo "number of rows " . $result;
} return $array_q;
} else return false;
}
}
*For the array [0] is the ID, 1 question id and [2] choice id.
Your problem stems from bad indenting, causing you to not realize where you were throwing the code: whether it was in the while loop, the if, the foreach, would have been totally a mystery.
Therefore, you had your if-statement inside your while loop, and thus were returning from within the while loop, rather than adding all the rows to the $rows array and then doing your if-statement.
You also would have been resetting the $array_q to empty, if you weren't returning prematurely, so that line needs to be moved out of the foreach loop.
You also have no MySQL connection being passed into the function! You're treating $_POST['x'] as if its a MySQL connection, and there's no way that it is!
function quiz_match($connection, $user_id, $question_id ,$choice_id)
{
//there is no way the next commented out line even works!
//$query = mysqli_query($_POST['x'], "SELECT * FROM `question_answers` WHERE `user_id` <> $user_id AND `question_id` = $question_id AND `choice_id` = $choice_id" );
$query = mysqli_query($connection, "SELECT * FROM `question_answers` WHERE `user_id` <> $user_id AND `question_id` = $question_id AND `choice_id` = $choice_id");
$rows = array(); //you should add this too
while($row = mysqli_fetch_assoc($query))
{
$rows[] = $row;
}
if (count($rows)>0)
{
$array_q = array(); //this should be here, not in the foreach loop
foreach ($rows as $key => $value)
{
$u_id = $value['user_id'];
//$array_q= []; //wrong place for this
array_push($array_q, $u_id, $value['question_id'], $value['choice_id']);
}
//$result = count($array_q);
//echo "number of rows " . $result;
return $array_q;
}
return false;
}
I'm working on a project for uni and have been using the following code on a testing server to get all devices from a table based on a user_id:
public function getAllDevices($user_id) {
$stmt = $this->conn->prepare("SELECT * FROM devices WHERE primary_owner_id = ?");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$devices = $stmt->get_result();
$stmt->close();
return $devices;
}
This worked fine on my testing server but returns this error when migrating over to the university project server:
Call to undefined method mysqli_stmt::get_result()
Some googling suggests using bind_result() instead of get_result() but I have no idea how to do this all fields in the table. Most examples only show returning one field
Any help would be much appreciated
Assuming you can't use get_result() and you want an array of devices, you could do:
public function getAllDevices($user_id) {
$stmt = $this->conn->prepare("SELECT device_id, device_name, device_info FROM devices WHERE primary_owner_id = ?");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$stmt->bind_result($id, $name, $info);
$devices = array();
while($stmt->fetch()) {
$tmp = array();
$tmp["id"] = $id;
$tmp["name"] = $name;
$tmp["info"] = $info;
array_push($devices, $tmp);
}
$stmt->close();
return $devices;
}
This creates a temporary array and stores the data from each row in it, and then pushes it to the main array. As far as I'm aware, you can't use SELECT * in bind_result(). Instead, you will annoyingly have to type out all the fields you want after SELECT
By now, you've certainly grasped the idea of binding to multiple variables. However, do not believe the admonitions about not using "SELECT *" with bind_result(). You can keep your "SELECT *" statements... even on your server requiring you to use bind_result(), but it's a little complicated because you have to use PHP's call_user_func_array() as a way to pass an arbitrary (because of "SELECT *") number of parameters to bind_result(). Others before me have posted a handy function for doing this elsewhere in these forums. I include it here:
// Take a statement and bind its fields to an assoc array in PHP with the same fieldnames
function stmt_bind_assoc (&$stmt, &$bound_assoc) {
$metadata = $stmt->result_metadata();
$fields = array();
$bound_assoc = array();
$fields[] = $stmt;
while($field = $metadata->fetch_field()) {
$fields[] = &$bound_assoc[$field->name];
}
call_user_func_array("mysqli_stmt_bind_result", $fields);
}
Now, to use this, we do something like:
function fetch_my_data() {
$stmt = $conn->prepare("SELECT * FROM my_data_table");
$stmt->execute();
$result = array();
stmt_bind_assoc($stmt, $row);
while ($stmt->fetch()) {
$result[] = array_copy($row);
}
return $result;
}
Now, fetch_my_data() will return an array of associative-arrays... all set to encode to JSON or whatever.
It's kinda crafty what is going on, here. stmt_bind_assoc() constructs an empty associative array at the reference you pass to it ($bound_assoc). It uses result_metadata() and fetch_field() to get a list of the returned fields and (with that single statement in the while loop) creates an element in $bound_assoc with that fieldname and appends a reference to it in the $fields array. The $fields array is then passed to mysqli_stmt_bind_result. The really slick part is that no actual values have been passed into $bound_assoc, yet. All of the fetching of the data from the query happens in fetch_my_data(), as you can see from the fact that stmt_bind_assoc() is called before the while($stmt->fetch()).
There is one catch, however: Because the statement has bound to the references in $bound_assoc, they are going to change with every $stmt->fetch(). So, you need to make a deep copy of $row. If you don't, all of the rows in your $result array are going to contain the same thing: the last row returned in your SELECT. So, I'm using a little array_copy() function that I found with the Google:
function array_copy( array $array ) {
$result = array();
foreach( $array as $key => $val ) {
if( is_array( $val ) ) {
$result[$key] = arrayCopy( $val );
} elseif ( is_object( $val ) ) {
$result[$key] = clone $val;
} else {
$result[$key] = $val;
}
}
return $result;
}
Your question suggests that you have MySQL Native driver (MySQLnd) installed on your local server, but MySQLnd is missing on the school project server. Because get_result() requires MySQLnd.
Therefore, if you still want to use get_result() instead of bind_result() on the school project server, then you should install MySQLnd on the school project server.
in order to use bind_result() you can't use queries that SELECT *.
instead, you must select individual column names, then bind the results in the same order. here's an example:
$stmt = $mysqli->prepare("SELECT foo, bar, what, why FROM table_name WHERE id = ?");
$stmt->bind_param("i", $id);
if($stmt->execute()) {
$stmt->bind_result($foo, $bar, $what, $why);
if($stmt->fetch()) {
$stmt->close();
}else{
//error binding result(no rows??)
}
}else{
//error with query
}
get_result() is now only available in PHP by installing the MySQL native driver (mysqlnd). In some environments, it may not be possible or desirable to install mysqlnd.
Notwithstanding, you can still use mysqli to do 'select *' queries, and get the results with the field names - although it is slightly more complicated than using get_result(), and involves using php's call_user_func_array() function. See example below which does a simple 'select *' query, and outputs the results (with the column names) to an HTML table:
$maxaccountid=100;
$sql="select * from accounts where account_id<?";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('i', $maxaccountid);
$stmt->execute();
print "<table border=1>";
print "<thead><tr>";
$i=0;
$meta = $stmt->result_metadata();
$query_data=array();
while ($field = $meta->fetch_field()) {
print "<th>" . $field->name . "</th>";
$var = $i;
$$var = null;
$query_data[$var] = &$$var;
$i++;
}
print "</tr></thead>";
$r=0;
call_user_func_array(array($stmt,'bind_result'), $query_data);
while ($stmt->fetch()) {
print "<tr>";
for ($i=0; $i<count($query_data); $i++) {
print "<td>" . $query_data[$i] . "</td>";
}
print "</tr>";
$r++;
}
print "</table>";
$stmt->close();
print $r . " Records<BR>";