How does PHP iterate over mysqli query results? - php

I'm learning to interact with a database in PHP. The code below works, but I do not understand how the loop iterates through $result.
<?php
require_once('./login.php');
$conn = new mysqli($hn, $un, $pw, $db);
if ($conn->connect_error) die("DIED: CONNECTION FAILED.");
$query= "SELECT * FROM table1";
$result = $conn->query($query);
if (!$result) die("DIED: QUERY FAILED.");
while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
$who = $row['WHO'];
$what = $row['WHAT'];
echo <<<_END
WHO: $who<br>
WHAT: $what<br>
_END;
}
$result->close();
$conn->close();
?>
I understand that while a $result element is available, it will be assigned to $row and processed in the loop. But how does the interpreter know to move to the next $result element?
The code even works when using a for loop instead, such as...
$row_count = $result->num_rows;
for($j = 0; $j < $row_count; $j++) {
$row = $result -> fetch_array(MYSQLI_ASSOC);
My question boils down to this: how does the interpreter know to use the next element in $result without needing something like $result[$j]?

The query returns a mysqli_result. Per the docs, this object is iterable http://php.net/manual/en/class.mysqli-result.php. So every time you call fetch_array(), the result object it is keeping track of which row it is currently on and returning the appropriate result, then moving forward one element in the result set. When there are no more results left, the function returns null which is evaluated as false thus terminating the loop.

Related

Using Arrays in MySQLi And PHP

Following is a typical OOP way to Connect and Retrive data from MySQL database using MySQLi and PHP.
Now I am a little bit confused on using the pure PHP arrays at this example:
Can some one please let me know if the $result is array or not? I mean in
$result = $mysqli_coonect->query($sql);
if so how come we didn't use the array() function or [] to create it?!
same thing happening with $row at:
$row = $result->fetch_assoc()
I am asking this because in order to load $row; to $results[] at $results[] = $row; we declared the $results as an array explicitly before the while() how come we are not doing this for other or vice versa?!
<?php
$mysqli_coonect = new mysqli($host_name, $user_name, $pass_word, $database_name, $port);
$sql = "SELECT * FROM books WHERE id <= 10";
$result = $mysqli_coonect->query($sql);
if (($result) && ($result->num_rows > 0))
{
$results = array();
while ($row = $result->fetch_assoc())
{
$results[] = $row;
}
$result->free();
}
$mysqli_coonect->close();
Always refer to the PHP documentation. It's great and you can easily find what you want.
http://php.net/manual/en/mysqli.query.php states that a query will return mixed in this case meaning either false if the query failed or mysqli_result object of the query was successful.
Getting down to business
$result = $mysqli->query($query) returns a mysqli_result object. This means that $result is now an object.
We then call the method fetch_assoc from our newly created $result (mysqli_result) object and store the results of the method in the variable $row (which if the method is successful will be an array). If you look at what fetch_assoc returns (http://php.net/manual/en/mysqli-result.fetch-assoc.php) you see that it returns an array.
We loop through our newly created $row array.

PHP - basic select query returning only the first row of mysql database

I've been running the query oh phpMyAdmin and it shows all the rows, but my query in php only returns the first row.
$result = $mydb -> query("SELECT * FROM music_sheet WHERE category='".$_REQUEST["submitter"]."'");
print(count($result)); //always returns 1
for ($x = 0; $x < count($result); $x++) {
$row = mysqli_fetch_row($result);
}
For reference, here's why count() is returning 1. From the manual:
If the parameter is not an array or not an object with implemented Countable interface, 1 will be returned. There is one exception, if array_or_countable [the parameter] is NULL, 0 will be returned.
Since $result is a resource (object) that is returned from your query, not an array which you would get within your loop getting the actual data out of the resource, count($resource) will return 1.
Your solution is of course to use mysqli_num_rows(). To retrieve data from this resource, you need to loop over it as you are doing, but either use mysqli_num_rows() in place of count(), or other (more common) ways of looping through a result set, like so:
while($row = mysqli_fetch_row($result)) {
// do stuff
}
You have to use mysqli_num_rows($result) function to count rows which are returned by MySQLi query.
Try this
echo mysqli_num_rows($result);
while($row = mysqli_fetch_row($result)) {
// write your code...
}
Use this instead of the for loop
the first thing that the query method returns to you is a resource/object. This query method always return a mysqli_result object for successful queries using SELECT, SHOW, DESCRIBE or EXPLAIN queries . For other successful queries mysqli_query() will return TRUE. For that reason it always count it as "1", what you should try is:
$result = $mydb -> query("SELECT * FROM music_sheet WHERE category='".$_REQUEST["submitter"]."'");
$numRows = $result->num_rows;
print(count($numRows)); //it should show you the total amount of rows
//verify the amount of rows before of tryng to loop over it
if ($numRows) {
while($object = mysqli_fetch_object($result)){
//for each loop you will have an object with the attributes of the row
echo $object->song_name;
}
}
This should work,
Regards.

PHP, MYSQL - Query fails but no error meessage appears

Back again, thanks for all the help last time. I'm running this query:
$query = "SELECT * FROM event where evLoc = ".$loc." AND evChar = ".$char;
var_dump($query);
$result = mysql_query($query, $con) or die('Error 1:'.mysql_error());
if ($result) {
$row = mysql_fetch_array($result) or die('Error 2:'.mysql_error());
var_dump(mysql_num_rows($result));
exit();
I get a message Error 2: but no mysql_error printed out. The var_dump($query) printed out a query that ran without errors in phpMyAdmin. The var_dump(mysql_num_rows($result)) did not print.
This is a case of being too cautious and applying error checking where it doesn't belong.
Don't call die() in partnership with a fetch call. The fetch intentionally returns FALSE when there are no rows available, so you don't have an error, just no rows.
// No rows were returned, wich is FALSE
$row = mysql_fetch_array($result) or die('Error 2:'.mysql_error());
Instead, don't call die() here:
$row = mysql_fetch_array($result);
if ($row) {
// you got something
}
Or this way:
if ($row = mysql_fetch_array($result)) {
// you got something.
}
If multiple rows are expected to be returned, fetch in a while loop.
while ($row = mysql_fetch_array($result)) {
// loops until you're out of rows
// or not at all if you have no rows
}
Obviously, your request returns 0 rows and mysql_fetch_array returns FALSE
Apply Single Quotes in the fields of your query
$query = "SELECT * FROM event where evLoc = '".$loc."' AND evChar = '".$char."'";
You can write these in short form too. Like
$query = "SELECT * FROM event where evLoc = '$loc' AND evChar = '$char'";
Next, you might want to change your fetch portion.
while($row = mysql_fetch_assoc($result)) {
....
}
When you use this, you will avoid the error you would receive when no rows are returned.

About the mysql_query -> mysql_fetch_array() procedure

Sample code:
$infoArray = array();
require_once("connectAndSelect.php");
// Connects to mysql and selects the appropriate database
$sql = "SOME SQL";
if($results = mysql_query($sql))
{
while($result = mysql_fetch_array($results, MYSQL_ASSOC))
{
$infoArray[] = $result;
}
}
else
{
// Handle error
}
echo("<pre>");
print_r($infoArray);
echo("</pre>");
In this sample code, I simply want to get the result of my query in $infoArray. Simple task, simple measures... not.
I would have enjoyed something like this:
$sql = "SOME SQL";
$infoArray = mysql_results($sql);
But no, as you can see, I have two extra variables and a while loop which I don't care for too much. They don't actually DO anything: I'll never use them again. Furthermore, I never know how to call them. Here I use $results and $result, which kind of represents what they are, but can also be quite confusing since they look so much alike. So here are my questions:
Is there any simpler method that I
don't know about for this kind of
task?
And if not, what names do you
give those one-use variables? Is
there any standard?
The while loop is really only necessary if you are expecting multiple rows to be returned. If you are just getting one row you can simply use mysql_fetch_array().
$query = "SOME SQL";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
For single line returns is the standard I use. Sure it is a little clunky to do this in PHP, but at least you have the process broken down into debug-able steps.
Use PDO:
<?php
/*** mysql hostname ***/
$hostname = 'localhost';
/*** mysql username ***/
$username = 'username';
/*** mysql password ***/
$password = 'password';
try {
$dbh = new PDO("mysql:host=$hostname;dbname=mysql", $username, $password);
$sql = "SELECT * FROM myTable";
$result = $dbh->query($sql)
//Do what you want with an actual dataset
}
catch(PDOException $e) {
echo $e->getMessage();
}
?>
Unless you are legacied into it by an existing codebase. DONT use the mysql extension. Use PDO or Mysqli. PDO being preferred out of the two.
Your example can be come a set of very consise statements with PDO:
// create a connection this could be done in your connection include
$db = new PDO('mysql:host=localhost;dbname=your_db_name', $user, $password);
// for the first or only result
$infoArray = $db->query('SOME SQL')->fetch(PDO::FETCH_ASSOC);
// if you have multiple results and want to get them all at once in an array
$infoArray = $db->query('SOME SQL')->fetchAll(PDO::FETCH_ASSOC);
// if you have multiple results and want to use buffering like you would with mysql_result
$stmt = $db->query('SOME SQL');
foreach($stmt as $result){
// use your result here
}
However you should only use the above when there are now variables in the query. If there are variables they need to be escaped... the easiest way to handle this is with a prepared statement:
$stmt = $db->prepare('SELECT * FROM some_table WHERE id = :id');
$stmt->execute(array(':id' => $id));
// get the first result
$infoArray = $stmt->fetch(PDO::FETCH_ASSOC);
// loop through the data as a buffered result set
while(false !== ($row = $stmt->fetch(PDO::FETCH_ASSOC))){
// do stuff with $row data
}

mysqli multiple queries - set variable produces boolean error/how to skip this?

Got the following simple query which works fine through phpmyadmin but when I add it to my php website no results are returned and no error/warning messages either. If I remove "SET #N=-1;" then it works fine.
<?php
$db_connect = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD, true);
mysql_select_db(DB_NAME, $db_connect);
$test_query = mysql_query("SET #N=-1;SELECT `id`, (#N:=#N+1) AS `mycount` FROM `mydb`;");
for ($i = 0; $i <= mysql_num_rows($test_query)-1; $i++) {
echo mysql_result($db_directorymap, $i, 0) . " " . mysql_result($db_directorymap, $i, 1) . "<br />";
}
?>
UPDATE: I just moved to mysqli but of course I'm still having a problem with the mysql statement and mysqli_multi_query. It seems when it runs the first part of the query the results returned are empty thus a boolean error is given. I'm guessing I have to skip the first set of results but I don't know how to do that?
It's because the mysql_query function will only accept one query, but you've given it two, separated by a semicolon. Try either:
Running each query separately (don't know if this will work):
mysql_query( "SET #N=-1" );
mysql_query( "SELECT `id`, (#N:=#N+1) AS `mycount` FROM `mydb`" );
Using mysqli with the multi_query function (or a PDO equivalent if there is one).
To answer your updated question: check the PHP manual page for multi_query. I think you'll want to use mysqli::next_result. Something like this, using procedural style:
mysqli_multi_query($link, $query);
mysqli_next_result($link);
if ($result = mysqli_store_result($link)) {
while ($row = mysqli_fetch_row($result)) {
printf("%s\n", $row[0]);
}
mysqli_free_result($result);
}
Multiple queries via mysql_query aren't supported, so I'd guess that it's only executing the SET command, and not the subsequent SELECT command.

Categories