tags:

views:

254

answers:

5
$allUsersResult = mysql_query("SELECT * FROM users");

// the purpose of this line was to grab the first row for use 
// separately in a different area than the while loop
$user = mysql_fetch_assoc($allUsersResult);


while($users = mysql_fetch_assoc($allUsersResult)){

 // the first row is not available here

}

So is this a bug or is it my fault for doing it wrong?

PS: this is only for example. I'm not using both $user and the while loop right next to each other like this, they are used in different places in the script.

+13  A: 

You need to drop

$allUsers = mysql_fetch_assoc($allUsersResult);

It's taking your first result row.

Answer to new question: No. It is not a design flaw in PHP. It's a flaw in your program design. You need to rethink what you are doing.

Why do you need the first value separated out? Are you relying on it to be a specific row from your table all of the time? If you alter your table schema it's very possible that the results will be returned to you using some other sorted order.

Perhaps if you tell us what you are trying to do we can give you some design suggestions.

jasonbar
OK, so what do I do if I need to use both? Do I have to run the query twice?
Chad
@Chad: I don't really know what you mean. You already have the first result? I guess you could add mysql_data_seek($allUsersResults, 0) before your loop..? Your variable naming is a bit confusing as `$allUsers` won't actually have "all the users".
jasonbar
The name $allUsers implies that it gets the whole table- it doesn't, it just gets one row.You could just set $allUsers=array(); then in the while loop do $allUsers[]=$users to copy each row into an array.
GoatRider
@jasonbar, thanks I fixed that. Also, your solution of adding mysql_data_seek($allUsersResult, 0); before the while loop solved the problem by putting the first row back. :)
Chad
Don't seek back to the start, that's just confusing. Instead, just do whatever you need to do to the first row outside the loop.
CurtainDog
So we've come to the conclusion that it's not possible get the first result of a mysql associative array and then do a while loop afterwards, unless you put the results into your own array. Am I right?
Chad
@Chad: Are you doing separate things with the first row before the loop? Why is it that you need that line of code in there?
musicfreak
Please leave your feedback on my answer below.
Chad
+9  A: 

It is your fault. By calling $allUsers = mysql_fetch_assoc($allUsersResult); first, you already fetch the first row from the result set. So just remove that line, and it should work as expected.

edit: Per request in comment.

$user = mysql_fetch_assoc($allUsersResult);
if ( $user ) // check if we actually have a result
{
    // do something special with first $user

    do
    {
        // do the general stuff with user
    }
    while( $user = mysql_fetch_assoc($allUsersResult) );
}
poke
ok, so what if I need the first row before doing a loop, how would you do it (without putting the whole result into your own array first)
Chad
Edited my answer to have an example of such a case.
poke
This assumes that both operations are taking place at the same spot in your code. Consider this: your mysql query is on page.php and you need first user in page.php but you need all the results(while loop) on page2.php, which is included in page.php after you've requested the first row. It seems that mysql_data_seek() is needed to put the first row back in.
Chad
I would never split such usages that far away. Splitting code into multiple files means, that the code should be able to run alone; but having a *local* mysql result passed into another file is in my opinion just bad style.
poke
This will not work because I don't need the first row in the same place in my code that I need the loop. And regarding your second reply, that is just an example, because people seem to think that a set of results should only be used all at once in one are. Even if it's in the same file, you should be able to use any specific row OR all rows anywhere in the file.
Chad
A: 

Which is considered as bad code by some IDEs (two statements in one row). Better:

$allUsersResult = mysql_query("SELECT * FROM users");
$user = mysql_fetch_assoc($allUsersResult);

while($user){

    // do stuff
    doStuff($user)

    // at last: get next result
    $user = mysql_fetch_assoc($allUsersResult)


}
Stefan
this just creates an infinite loop
Chad
@Chad No, it doesn't.
deceze
This is ugly, messy and if my IDE told me it was better style, I'd go find another IDE.
symcbean
A: 

I'll go ahead and answer my own question on this one:

    $allUsersResult = mysql_query("SELECT * FROM users");

    // transfer all rows to your own array immediately
    while($user = mysql_fetch_assoc($allUsersResult)){
       $allUsers[] = $user;
     }

    // use first row however you like anywhere in your code
    $firstRow = $allUsers[0];

    // use all rows however you like anywhere in your code
    foreach($allUsers as $user){
      // do whatever with each row ($user). Hey look they're all here! :)
    }
Chad
The only downside is you have to do the transferring part for every different query (but of course you can create a function to handle that for you). If there is a better way please let me know.
Chad
Chad, you asked for feedback here. This appears to be a much cleaner and more straightforward way to go about the situation you were describing. This makes much more sense than getting the first row and then resetting the internal result pointer. (It's likely I would have picked this or similar, still not knowing the full situation). I'm glad you decided to examine your program design, and to change it to better fit your situation.
jasonbar
@jasonbar This is the only way I knew of doing it all along, and I expected to get exactly this as an answer from almost everyone. I just though it should be possible with some built in PHP functions.
Chad
If you properly group all your database related code into functions and/or classes, you'd most likely do this anyway to every result set and just return an array.
deceze
A: 

When you use mysql_fetch_assoc(), you are basically retrieving the row and then advancing the internal result pointer +1.

To better explain, here is your code:

$allUsersResult = mysql_query("SELECT * FROM users");
//Result is into $allUsersResult... Pointer at 0


$user = mysql_fetch_assoc($allUsersResult);
// $user now holds first row (0), advancing pointer to 1 


// Here, it will fetch second row as pointer is at 1...
while($users = mysql_fetch_assoc($allUsersResult)){

 // the first row is not available here

}

If you want to fetch the first row again, you do not need to run the query again, simply reset the pointer back to 0 once you have read the first row...

$allUsersResult = mysql_query("SELECT * FROM users");
//Result is into $allUsersResult... Pointer at 0


$user = mysql_fetch_assoc($allUsersResult);
// $user now holds first row (0), advancing pointer to 1 

// Resetting pointer to 0
mysql_data_seek($allUsersResult, 0);

// Here, it will fetch all rows starting with the first one
while($users = mysql_fetch_assoc($allUsersResult)){
  // And the first row IS available
}

PHP Documentation: mysql_data_seek()

Andrew Moore