I grab random rows, 100 at a time and once used I mark the column 'used' with a 1. I need to reset all those with a 1 when it has no more that are marked 0 to pick from. Here is my code for this...
$result = mysqli_query($res, "SELECT id, unit_id, shown FROM units WHERE suspended = '0' AND used = '0' ORDER BY RAND() LIMIT 100");
while($myrow = mysqli_fetch_array($result)){
if (!$result){
$result2 = mysqli_query($res, "UPDATE units SET used='0' WHERE used =
'1'");
}
else{
other code here
}
}
$res->close();
I have also tried this:
if ($myrow[id] == ''){
But that does not work either. I just need to know when it has marked all of them used so it can reset 'used' back to 0 so it will start over again.
I have also tried moving the if statement outside the while and it still is not working.
It should be noted that this runs on a cron.
Set $i = 0; outside the while and inside it add 1. After the while loop check if the $i is less than 100 and if it is then for sure you reached the end of the list, but if $i is equal 100 then you need to check with dB query, because there is a chance that you have result with the last 100 records and again it will be the end of the list.
Related
Before I was using this code to count rows
echo $db_handle->numRows("SELECT * FROM orders WHERE DATE(reattemptdate) = CURDATE()");
than i found it effects on performance, than i tried to use below code, but it not giving correct number of rows, what wrong i done in below code ?
$sqldelivery = "SELECT COUNT(*) as count FROM orders WHERE DATE(reattemptdate) = CURDATE()";
$resultdeliverys = $db_handle->runSelectQuery($sqldelivery);
$numrowsresultdelivery =count($resultdeliverys);
echo $numrowsresultdelivery;
Database connection code :
function numRows($query) {
$result = mysqli_query($this->conn,$query);
$rowcount = mysqli_num_rows($result);
return $rowcount;
}
In your second code, the query will always return 1 row - a row with the column count being the number of rows, so...
$numrowsresultdelivery =count($resultdeliverys);
Will probably always be 1, you need something like...
$numrowsresultdelivery =$resultdeliverys[0]['count'];
to extract the count field from the first row of the result.
(Note I don't know if this is the right notation, but it's the principle of needing a field from the result rather than the number of results.)
You must already have the count number via $resultdeliverys->count.
$sqldelivery = "SELECT COUNT(*) as count FROM orders WHERE DATE(reattemptdate) = CURDATE()";
$resultdeliverys = $db_handle->runSelectQuery($sqldelivery);
// Try this to know if it's returning array or object
var_dump($resultdeliverys);
i try something like this :
function userrank($userid){
$sql = mysql_query("SELECT * FROM users ORDER BY atacs DESC");
$i = 1;
while ($row = mysql_fetch_assoc($sql)) {
if ($row['username'] == $userid) {
echo 'You are on ' . $i . ' in the general leaderbord';
}
}
}
On the leaderboard it shows me the rank correctly, but i want to show me on another page too , on the "youraccount" page , for this i try to make this function.
what is wrong ?
Basically what you're doing here is counting how many users have an atacs greater than or equal to $userid's atacs. Problems with this:
Terribly inefficient. Note the database retrieves and sends to your
while loop an entry for every user, even those who have an atacs
less than the $userid. All but one of these while loop iterations
does nothing by design. Lots of wasted time sending data from the
database to PHP, which doesn't even use it.
Pulls way more data back
than is necessary. You end up with every row for every user in
your entire users table - but your result is just a scalar number
( how many users with > score ).
Actually gives you wrong results
in the case that your score is tied with others'. In this case some
users with the same score may be counted as "above" the user, others
as "below the users".
Databases are good at iterating over data; it's
all "locally" accessible and the database engine can make many
optimizations if you can describe in SQL what you are trying to
accomplish. So instead of doing it that way, why not just do
everything in the database?
set #user_atacs = ( select atacs from users where id = 12 );
select count(*) +1 from users where atacs > #user_atacs;
I've mocked up the table here: http://sqlfiddle.com/#!2/ff9a86/3
This solution essentially just counts the number of users with a higher atacs than the current user. All users with the same score will get the same rank, and the next rank will be appropriately higher, so it doesn't suffer from any of your method's errors.
As a final note, the most appropriate way to do something like leaderboards is probably to precompute the leaderboard periodically and then use the results to show each user's position in the leaderboards, rather than trying to compute it on the fly for each user. But that's even farther out of scope :)
You have to increment $i. I'm Assuming that the leader board order is represented by the result of your query. So, if true, change your code as follows:
function userrank($userid){
$sql = mysql_query("SELECT * FROM users ORDER BY atacs DESC");
$i =0; // starts out with an unknown rank.
while ($row = mysql_fetch_assoc($sql)) {
$i++; // increment $i here.
if ($row['username'] == $userid) {
echo 'You are on ' . $i . ' in the general leaderbord';
}
}
}
The $i will increment for sure. So, if it is not working still, I'd look to see what the result of your query is. Try echoing $row['username'] and see what the value is and then compare that to the echoed calue of $userid.
I'm a beginner at php, so please be gentle.. :-)
I've looked for answers, but time and time again I get the same error. I can't find the error and it's drivin' me nuts!
$query = "SELECT position FROM pages WHERE subject_id = '$subject_id' ORDER BY position DESC LIMIT 1";
$bla = mysql_query($query, $connection);
$position = $bla[0];
$position += 1;
Ok, the above code is at the top of my page. From what I understand, this should do the following: get the column called 'position' from the table 'pages' where the 'subject_id' matches the subject_id I passed, and sort this and pick 1 value (which would be the highest). So I would now have 1 column with 1 value. I then grab that value, put it in 'position' and increment that with 1.
But the error I get back is: "Column count doesn't match value count at row 1"
Again, I'm a beginner (I'm used to another language), so this is probably something small and stupid that I forgot/did wrong.. can anyone help me out?
mysql_query() returns a statement handle, not the data you want. You have to fetch a row first:
$bla = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_row($bla);
$position = $row[0] + 1;
You could just change your query to:
$query = "UPDATE pages SET position=position+1 WHERE subject_id = '$subject_id' ORDER BY position DESC LIMIT 1";
then simply run
mysql_query($query, $connection);
Obviously, if you have two subject_ids with the same highest value, only one will update - but the way you have your script set up now would do the same anyway.
I want to select all records from my table and loop through all those records until I get to the record where the numtimespaid column is equal to 0. Once I find that column I want to update it to 2 for that record and then exit out. Here is what I have that is not working correctly:
$query1 = "SELECT * FROM ".$line." ORDER BY datestamp, timestamp";
$result1 = mysql_query($query1) or die(mysql_error());
while($row = mysql_fetch_array($result1)){
if ($row[numtimespaid] == 0) {
$queryupdate="UPDATE ".$line." SET numtimespaid=1";
$resultu=mysql_query($queryupdate);
break;
}
}
Any ideas as to what I'm doing wrong and/or the right way of doing this?
There is no need whatsoever to loop over rowset from a SELECT statement. You can simply update the first row with that value. This query will update exactly one record matching numtimespaid = 0. If you want to update all rows matching that criterion, just remove the LIMIT 1.
$result = mysql_query("UPDATE $line SET numtimespaid=1 WHERE numtimespaid = 0 ORDER BY datestamp, timestamp LIMIT 1");
By the way, we don't know what the contents of $line are, but hopefully you have properly filtered that value if it comes from user input. If it does comes from user input, it's recommended to check its value against a whitelist of possible table names:
// $line can be one of table1,table2,table3
if (!in_array($line, array('table1','table2','table3')) {
// FAIL, don't execute the query
}
if ($row[numtimespaid] == 0) {
Generally gets interpreted as numtimespaid being an undefined constant. Put quotes around it, like this:
if ($row['numtimespaid'] == 0) {
Then, realize Michael's answer is just better overall.
I have a table with roughly 1 million rows. I'm doing a simple program that prints out one field from each row. However, when I started using mysql_pconnect and mysql_query the query would take a long time, I am assuming the query needs to finish before I can print out even the first row. Is there a way to process the data a bit at a time?
--Edited--
I am not looking to retrieve a small set of the data, I'm looking for a way to process the data a chunk at a time (say fetch 10 rows, print 10 rows, fetch 10 rows, print 10 rows etc etc) rather than wait for the query to retrieve 1 million rows (who knows how long) and then start the printing.
Printing one million fields will take some time. Retrieving one million records will take some time. Time adds up.
Have you profiled your code? I'm not sure using limit would make such a drastic difference in this case.
Doing something like this
while ($row = mysql_fetch_object($res)) {
echo $row->field."\n";
}
outputs one record at a time. It does not wait for the whole resultset to be returned.
If you are dealing with a browser you will need something more.
Such as this
ob_start();
$i = 0;
while ($row = mysql_fetch_object($res)) {
echo $row->field."\n";
if (($i++ % 1000) == 0) {
ob_flush();
}
}
ob_end_flush();
Do you really want to print one million fields?
The customary solution is to use some kind of output pagination in your web application, showing only part of the result. On SELECT queries you can use the LIMIT keyword to return only part of the data. This is basic SQL stuff, really. Example:
SELECT * FROM table WHERE (some conditions) LIMIT 40,20
shows 20 entries, starting from the 40th (off by one mistakes on my part may be possible).
It may be necessary to use ORDER BY along with LIMIT to prevent the ordering from randomly changing under your feet between requests.
This is commonly needed for pagination. You can use the limit keyword in your select query. Search for limit here:
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).
With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1):
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15
To retrieve all rows from a certain offset up to the end of the result set, you can use some large number for the second parameter. This statement retrieves all rows from the 96th row to the last:
SELECT * FROM tbl LIMIT 95,18446744073709551615;
With one argument, the value specifies the number of rows to return from the beginning of the result set:
SELECT * FROM tbl LIMIT 5; # Retrieve first 5 rows
In other words, LIMIT row_count is equivalent to LIMIT 0, row_count.
You might be able to use
Mysqli::use_result
combined with a flush to output the data set to the browser. I know flush can be used to output data to the browser at an incremental state as I have used it before to do just that, however I am not sure if mysqli::use_result is the correct function to retrieve incomplete result sets.
This is how I do something like that in Oracle. I'm not sure how it would cross over:
declare
my_counter integer := 0;
begin
for cur in (
select id from table
) loop
begin
-- do whatever your trying to do
update table set name = 'steve' where id = cur.id;
my_counter := my_counter + 1;
if my_counter > 500 then
my_counter := 0;
commit;
end if;
end;
end loop;
commit;
end;
An example using the basic mysql driver.
define( 'CHUNK_SIZE', 500 );
$result = mysql_query( 'select count(*) as num from `table`' );
$row = mysql_fetch_assoc( $result );
$totalRecords = (int)$row['num'];
$offsets = ceil( $totalRecords / CHUNK_SIZE );
for ( $i = 0; $i < $offsets; $i++ )
{
$result = mysql_query( "select * from `table` limit " . CHUNK_SIZE . " offset " . ( $i * CHUNK_SIZE ) );
while ( $row = mysql_fetch_assoc( $result ) )
{
// your per-row operations here
}
unset( $result, $row );
}
This will iterate over your entire row volume, but do so only 500 rows at a time to keep memory usage down.
It sounds like you're hitting the limits of various buffer sizes within the mysql server... Some methods you could do would be to specify the field you want in the SQL statement to reduce this buffer size, or play around with the various admin settings.
OR, you can use a pagination like method but have it output all on one page...
(pseudocode)
function q($part) {
$off = $part*SIZE_OF_PARTITIONS;
$size = SIZE_OF_PARTITIONS;
return( execute_and_return_sql('SELECT `field` FROM `table` LIMIT $off, $size'));
}
$ii = 0;
while ($elements = q($ii)) {
print_fields($elements);
$ii++;
}
Use mysql_unbuffered_query() or if using PDO make sure PDO::MYSQL_ATTR_USE_BUFFERED_QUERY is false.
Also see this similar question.
Edit: and as others have said, you may wish to combine this with flushing your output buffer after each batch of processing, depending on your circumstances.