I was messing around with how to do queries from MySQL and show them on PHP and I stumbled upon something:
This is the table I'm doing the query to:
$query = mysqli_query($conexion, "SELECT * FROM notas");
while($nota = mysqli_fetch_assoc($query)){
var_dump($nota);
echo $nota["Descripcion"];
}
Whenever I use a while() to display all the results of the query, it works. This table have 2 rows and both of them are showing.
Result of the var_dump($notas):
But whenever I use a foreach(), it just returns me the last result of the query.
$query = mysqli_query($conexion, "SELECT * FROM notas");
foreach(mysqli_fetch_assoc($query) as $valor){
var_dump($valor);
}
Result of the var_dump($valor):
Is there any reason why? I'm doing something wrong in the foreach() loop? I really can't tell. I would just say "fudge it", accept it and only use while loops to display queries, but, you know, want to know if I was doing something wrong or not understanding something.
The second version is looping through the columns, not the rows. It's equivalent to:
$row = mysqli_fetch_assoc($query);
foreach ($row as $valor) {
var_dump($valor);
}
You can see here that it's just fetching one row, which is an associative array, then looping through the elements of that array.
foreach (<expression> as <variable>) doesn't re-evaluate the expression every time through the loop. It executes it once, saves that array, then loops through the array elements.
The mysqli_result object is iterable, so you can do:
foreach($query as $valor) {
var_dump($valor);
}
You can also call mysqli_fetch_all($query), which will return a 2-dimensional array of all the results, and then loop through that. But if the query returns many results, this will use lots of memory.
Related
Is there a way to enable the use of fetch_assoc() several times on the same page with prepared statements?
$data = $conn->prepare("SELECT * FROM some_table WHERE id=?");
$data->bind_param('i',$id);
$data->execute();
$result = $data->get_result();
I'd like to be able to use fetch_assoc() on the same page as many times as I want as many different ways I want. If I want to loop twice, I should be able to do that. If I want to loop and do a single fetch, I should also be able to do that. Right now it seems, once fetch_assoc() is being used once, it cannot be used again on the same page.
In a loop
while($row = $result->fetch_assoc()){
...
}
Single fetch
$user = $result->fetch_assoc();
$first_name = $user['first_name'];
While technically possible (Nick shows how) to rewind the mysqli_result object, many people find it cumbersome to work with mysqli_result at all. It's much easier to fetch all the records into a PHP array and work with a multidimensional array instead of the mysqli_result object.
$result = $data->get_result()->fetch_all(MYSQLI_ASSOC);
This way you can do whatever you want with this array. You can filter, you can loop many times, you can use all the standard array functions in PHP.
$resultsFiltered = array_filter($results, fn($e) => $e['someColumn']>200);
foreach($resultsFiltered as $row) {
// only records with someColumn > 200
}
You can use mysqli_result::data_seek to reset the result pointer after each usage so you can loop over the results multiple times. For example:
while($row = $result->fetch_assoc()){
...
}
$result->data_seek(0);
while($row = $result->fetch_assoc()){
...
}
Is there a way to enable the use of fetch_assoc() several times on the same page with prepared statements?
$data = $conn->prepare("SELECT * FROM some_table WHERE id=?");
$data->bind_param('i',$id);
$data->execute();
$result = $data->get_result();
I'd like to be able to use fetch_assoc() on the same page as many times as I want as many different ways I want. If I want to loop twice, I should be able to do that. If I want to loop and do a single fetch, I should also be able to do that. Right now it seems, once fetch_assoc() is being used once, it cannot be used again on the same page.
In a loop
while($row = $result->fetch_assoc()){
...
}
Single fetch
$user = $result->fetch_assoc();
$first_name = $user['first_name'];
While technically possible (Nick shows how) to rewind the mysqli_result object, many people find it cumbersome to work with mysqli_result at all. It's much easier to fetch all the records into a PHP array and work with a multidimensional array instead of the mysqli_result object.
$result = $data->get_result()->fetch_all(MYSQLI_ASSOC);
This way you can do whatever you want with this array. You can filter, you can loop many times, you can use all the standard array functions in PHP.
$resultsFiltered = array_filter($results, fn($e) => $e['someColumn']>200);
foreach($resultsFiltered as $row) {
// only records with someColumn > 200
}
You can use mysqli_result::data_seek to reset the result pointer after each usage so you can loop over the results multiple times. For example:
while($row = $result->fetch_assoc()){
...
}
$result->data_seek(0);
while($row = $result->fetch_assoc()){
...
}
I have found some PHP code that connects to a MySQL database and gets the column CityName for each row of the table Cities. I'm curious why while() loop is used and not for() or foreach. So here are my questions regarding how while() works in case of looping through arrays:
First, isn't $row variable an 2D array which it's rows contains the list of cities from the SQL query and it's columns contain the columns of each row of the query?
If this is the case, couldn't for() or foreach() be used to loop through the $row array?
Second, how does while() know when the array ends using only $row = $stmt->fetch_assoc() in the while()'s first line in order to end the loop?
Third, how does while() move to the next row of the $row array without using next() at the end of the loop?
And last but not least, how does echo $row['CityName']; output the city name of each row of the $row array without specifying the row of the array to use but only it's column CityName?
Thanks for any answers.
$query="SELECT CityName FROM Cities";
if($stmt = $connection->query("$query"))
{
while ($row = $stmt->fetch_assoc())
{
echo $row['CityName'];
}
}
else
{
echo $connection->error;
}
You could loop through $row, because it is an array (a simple array, not a 2d array); but you're not looping through an array called $row with the while, you're iterating over the resultset returned by $stmt->fetch_assoc() - which isn't an array- and assigning the value of a single returned row to $row in that statement (note the = for assignment) from the resultset.
while itself doesn't magically move any pointer; it's the call to $stmt->fetch_assoc() that not only returns a single row result, but moves the resultset pointer to the next result (and determines when it has reached the end of the resultset)
while($this_is_true){
// do this
}
# if the condition is not true for this while stmt, it will not execute (not even once)
do{
// stuff here
} while($thisIsTrue);
# even if the condition isn't true, a do-while executes at least once (the first time)
The point is that they are using a while() because it's a lazy way to say "only do it if it's true", so they don't have to check if it's true before they loop through it. WIth a for loop, you need to know the number of results you are looping through. For a do, you need to know that there are results before you attempt to use the results (echo). So, you use a while() to check if it's valid and then execute it, with just that piece of code.
Personally, I like to do...
if($query->num_rows > 0){
$query->bind_result($bindvar);
while($query->fetch()){
// do stuff
}
$query->close();
} else {
// no results found
}
You can use foreach instead of while. At least if stmt is a mysqli_result and you PHP version is not terribly outdated (newer than 5.4). In that case your loop would be:
foreach($stmt as $row)
{
echo $row['CityName'];
}
But this does not mean that $stmt is a 2D array. It's an object that implements the Traversable interface. That means that the foreach loop will implicitly invoke the required methods.
I am very new to PHP and I realise I have a lot to learn, especially about SQL injection attacks and the new php 5.5 oo stuff.
However, whilst I am learning I try to play about a bit and experiment and I have come across a problem. I need to get all results from one column (team_name) of my query into an array (zero indexed would be easier) so that I can put those results into a foreach loop to create a fixture list. For example - this is what I would like to do with the data...
foreach ($teams as $team) {
foreach ($teams as $opposition) {
if ($team != $opposition) {
echo "$team versus $opposition";
}
}
}
So my sql query is as follows...
$query="select * from pool_a";
$result=mysql_query($query);
$num=mysql_num_rows($result);
Then I can easily output the data I am looking for as follows;
echo "<table>";
for ($i=0;$i<$num;$i++) {
$teams=mysql_result($result,$i,'team_name');
echo "<tr><td>$teams</tr>";
}
echo "</table>";
But what I can't do is get the data into an array. I thought that data that came back from a msql_query such as the above always came back as an array, no matter the number of results, but if I run an is_array() check on $teams, it returns false.
I have tried using explode (after adding a comma after each team name and trimming the last one off) and then using a foreach loop but it only ever returns the value associated with the index [0]. I should add here that although the key is 0, the actual value I get is the LAST in the list when echoed as above, which I also don't understand.
Any help would be much appreciated.
Thanks
$team_names = array();
while ($row = mysql_fetch_assoc($result)) {
$team_names[] = $row['team_name'];
}
mysql_fetch_assoc, mysql_fetch_row, and mysql_fetch_array all return a row as an array (they differ in how it's indexed). But mysql_result just returns a single item from the result, so it doesn't return an array.
You could do the same thing as above with your use of mysql_result, but you still have to push them onto the result array yourself:
for ($i=0;$i<$num;$i++) {
$team=mysql_result($result,$i,'team_name');
$team_names[] = $team;
}
To get the results of the query into an array, you can do this
$query="select * from pool_a";
$result=mysql_query($query);
$result_arr = mysql_fetch_array($result);
$num=mysql_num_rows($result);
However, consider using the PDO drivers to connect to the database. It's far superior to doing it procedurally, and it's safer as Prepared Statments will help protect you against injection attacks. The method you're using is deprecated.
Instead of using mysql_result try using mysql_fetch_array($result, MYSQL_ASSOC)
This function will give you an array of whatever your result from MySQL is.
Okay, so I realize that when do:
//connection code;
//query code;
//$result= mysqli_query();
$row= mysqli_fetch_array($result);
you create an associative array where the column names from your table are the keys for the data in the respective row.
Then you can use:
while ($row= mysqli_fetch_array($result))
{
//code to echo out table data.
}
My question is how does the while loop go to the next row after each iteration? I thought that was what foreach loops were for?
From http://www.php.net/manual/en/function.mysql-fetch-array.php
array mysql_fetch_array ( resource $result [, int $result_type = MYSQL_BOTH ] )
Returns an array that corresponds to the fetched row and moves the internal data pointer ahead.
Many functions that return a result set do so by returning an array that you can do a foreach() on like you are used to. This is not always the case however, especially with database functions. mysqli_fetch_array fetches just a single row, or returns boolean false if there are no more remaining. This is how the loop works: the expression evaluates to true as long as there is a row to process.
The reason for this construction is mainly efficiency. Fetching database rows can be a performance critical operation, and there are cases where not all rows are needed. In these situations this approach will give more flexibility. Fetching rows one-by-one is also more memory-friendly since not all result data will have to be loaded into memory at once.
Mysqli actually has a function that does fetch the entire result set in an array: mysqli_fetch_all. You will be able to foreach() over that.
mysql_fetch_array simply fetches the next row of the result set from your mysql query and returns the row as an array or false if there are no more rows to fetch.
The while loops continually pulls the results, one at a time from the result set and continues until mysql_fetch_array is false.
A foreach loop loops through each value of an array. As mysql_fetch_array only pulls one result and therefore the value of count($row) would be 1 every time.
Each time the while loop runs, it executes the function mysql_fetch_array and gets the next result. It does that until there aren't more results to show.
mysql_fetch_array returns an array of strings that corresponds to the fetched row, or FALSE if there are no more rows. If row exists then get data.
I hope this has answered you q. Its hard to understand what you mean
This part fetches one row at a time
$row = mysqli_fetch_array($result);
Putting it into a while loop makes it fetch one row at a time, until it does not fetch a row because there are no more to be fetched.
The alternative would be to fetch all the rows, then loop through them with a foreach
$rows = mysql_fetch_all($result);
foreach($rows as $row){
// do something with row
}
For this to work, you have to make yourself a mysql_fetch_all function, which of course has the original while loop in it...
function mysql_fetch_all($result)
{
$all = array();
while($thing = mysql_fetch_assoc($result)) {
$all[] = $thing;
}
return $all;
}
This works due to the SQL connector storing the current state of the query (i.e. the next result row to return) inside the result.
If you want a similar example, it works like reading from a file, where you're able to use similar constructs:
while ($line = fgets($fp, 1000)) {
// ...
}
Behind the scenes (and depending on the language, interpreter, compiler, etc.) for and while essentially result in the same code. The difference is, depending on what your code should do, one approach could be more readable than the other.
Take the following two loops as an example. Both do exactly the same.
for ($i = 0; $i < 10; $i++) {
// ...
}
$i = 0;
while ($i < 10) {
// ...
$i++;
}