Using count(*) and mysql_fetch_object() at the same time? - php

I want to count all the rows and at the same time list them as I usually do, using mysql_fetch_object. I thought I'd do something like this;
$total = mysql_query("SELECT *, COUNT(*) AS totalfound FROM img WHERE state='0'");
But I can't seem to wrap my head around how to get the values out - I just get the first item in the table when I run this;
while ($record = mysql_fetch_object($total)) { echo $record->id; }
If I want to get the totalfound I could do this;
$result = mysql_fetch_assoc($total);
$count = $result['totalfound'];
...but then I can't get the rest. I know I'm thinking wrong but can't seem to get it to work. Can you guys please help me out? Thanks!
Once thing I forgot to mention: mysql_num_rows is too slow, I was thinking of using count(*) instead. As an example, mysql_num_rows on the entire table takes everything from 3 to 9 seconds, and a count(*) always takes 0.6 seconds, getting the same results.

A count is an aggregate function, you cannot select both rows and aggregates without using group by. MySQL will let you do it without the group by, and will produce unpredictable results.
Just use the query without count to get the rows, and use mysql_num_rows() on the result.
Edit: If mysql_num_rows() is slow, you must be returning a lot of rows. You'd then better execute two queries, one simply select count(*) as numrows ..., and one to retreive your data.
Try to add proper indexes and the count(*) will execute within a few miliseconds.
You really don't want this in one query. Every row will then have a column that states how many rows there are, which is unrelated to that row.

Why not just list them normally and get the count by the inbuilt function?
$result = mysql_query("SELECT * FROM img WHERE state='0'");
$count = mysql_num_rows($result);
while ($row = mysql_fetch_array($result))
{
//do your thing here
}
Editing in response to your edit
In normal circumstances, where you only want the Count, a Count() would be far faster than mysql_num_rows() because Count() would only return the count. In your case, since you want the records anyway, mysql_num_rows() should be faster.

If I understand what you need, I think you could use:
$result = mysql_query("SELECT * FROM img WHERE state='0'");
$num_rows = mysql_num_rows($result);
With $result you can get all rows the way you're used to, while $num_rows has the number of returned rows from database.

Aside from the Marco's right answer,
why can't you make it the same way, echo $record->totalfound;?
As for the "mysql_num_rows being slow" - it is no more a delusion.
You have just heard something but didn't get the point.
mysql_num_rows itself isn't being slow by any means.
it is gathering data rows being slow, not getting them count.
mysql_num_rows indeed is slower than count(*) if you need only that number, not all the data
but if you are getting your data anyway, mysql_num_rows is exactly what you need

Use KISS theory and do the below
while ($record = mysql_fetch_object($total)) {$totalData[] = $record; }
count($totalData) // returns total number of rows
Count

My dear haven't you listen about mysql_num_rows
$total = mysql_query("SELECT * FROM img WHERE state='0'");
$total_found=mysql_num_rows($total);

Related

Using count_all_results or get_compiled_select and $this->db->get('table') lists table twice in query?

How do I use get_compiled_select or count_all_results before running the query without getting the table name added twice? When I use $this->db->get('tblName') after either of those, I get the error:
Not unique table/alias: 'tblProgram'
SELECT * FROM (`tblProgram`, `tblProgram`) JOIN `tblPlots` ON `tblPlots`.`programID`=`tblProgram`.`pkProgramID` JOIN `tblTrees` ON `tblTrees`.`treePlotID`=`tblPlots`.`id` ORDER BY `tblTrees`.`id` ASC LIMIT 2000
If I don't use a table name in count_all_results or $this->db->get(), then I get an error that no table is used. How can I get it to set the table name just once?
public function get_download_tree_data($options=array(), $rand=""){
//join tables and order by tree id
$this->db->reset_query();
$this->db->join('tblPlots','tblPlots.programID=tblProgram.pkProgramID');
$this->db->join('tblTrees','tblTrees.treePlotID=tblPlots.id');
$this->db->order_by('tblTrees.id', 'ASC');
//get number of results to return
$allResults=$this->db->count_all_results('tblProgram', false);
//chunk data and write to CSV to avoid reaching memory limit
$offset=0;
$chunk=2000;
$treePath=$this->config->item('temp_path')."$rand/trees.csv";
$tree_handle=fopen($treePath,'a');
while (($offset<$allResults)) {
$this->db->limit($chunk, $offset);
$result=$this->db->get('tblProgram')->result_array();
foreach ($result as $row) {
fputcsv($tree_handle, $row);
}
$offset=$offset+$chunk;
}
fclose($tree_handle);
return array('resultCount'=>$allResults);
}
To count how many rows would be returned by a query, essentially all the work must be performed. That is, it is impractical to get the count, then perform the query; you may as well just do the query.
If your goal is to "paginate" by getting some of the rows, plus the total count, that is essentially two separate actions (that may be combined to look like one.)
If the goal is to estimate the number of rows, then SHOW TABLE STATUS or SELECT Rows FROM information_schema.TABLES WHERE ... gives you an estimate.
If you want to see if there are, say "at least 100 rows", then this may be practical:
SELECT 1 FROM ... WHERE ... ORDER BY ... LIMIT 99,1
and see if you get a row back. However, this may or may not be efficient, depending on the indexes and the WHERE and the ORDER BY. (Show us the query and I can elaborate.)
Using OFFSET for chunking is grossly inefficient. If there is not a usable index, then it is performing essentially the entire query for each chunk. If there is a usable index, the chunks are slower and slower. Here is a discussion of why OFFSET is not good for "pagination", plus an efficient workaround: Pagination . It talks about how to "remember where you left off " as an efficient technique for chunking. Fetch between 100 and 1000 rows per chunk.
The flaw in your code is that it aims to select a subset of some records and their total count in the same query. This is impossible in MySQL, so you cannot generate such a query, hence, you get the error as mentioned. The problem is that if you do a
select ... from t where ... limit 0, 2000
then you get maximum 2000 records, so, if the total records matching the criteria have a count that is greater than the limit, then you will not get accurately the count from above, so, in that case you need a
select count(1) from t where ...
This means that you need to build your actual query (the code below your count_all_results call), see whether the number of results reaches the limit. If the number of results does not reach the limit, then you do not need to perform a separate query in order to get the count, because you can compute $offset * $chunk + $recordCount. However, if you get as many records as they can be, then you will need to build another query, without the order_by call, since the count is independent of your sort and get the counts.
$this->db->count_all_results()
Counting the number of returned results with count_all_results()
It's useful to count the number of results returned—often bugs can arise if a section of code which expects to have at least one row is passed zero rows. Without handling the eventuality of a zero result, an application may become unpredictably unstable and may give away hints to a malicious user about the architecture of the app. Ensuring correct handling of zero results is what we're going to focus on here.
Permits you to determine the number of rows in a particular Active Record query. Queries will accept Query Builder restrictors such as where(), or_where(), like(), or_like(), etc. Example:
echo $this->db->count_all_results('my_table'); // Produces an integer, like 25
$this->db->like('title', 'match');
$this->db->from('my_table');
echo $this->db->count_all_results(); // Produces an integer, like 17
However, this method also resets any field values that you may have passed to select(). If you need to keep them, you can pass FALSE as the second parameter:
echo $this->db->count_all_results('my_table', FALSE);
get_compiled_select()
The method $this->db->get_compiled_select(); is introduced in codeigniter v3.0 and compiles active records query without actually executing it. But this is not a completely new method. In older versions of CI it is like $this->db->_compile_select(); but the method has been made protected in later versions making it impossible to call back.
// Note that the second parameter of the get_compiled_select method is FALSE
$sql = $this->db->select(array('field1','field2'))
->where('field3',5)
->get_compiled_select('mytable', FALSE);
// ...
// Do something crazy with the SQL code... like add it to a cron script for
// later execution or something...
// ...
$data = $this->db->get()->result_array();
// Would execute and return an array of results of the following query:
// SELECT field1, field1 from mytable where field3 = 5;
NOTE:- Double calls to get_compiled_select() while you’re using the Query Builder Caching functionality and NOT resetting your queries will results in the cache being merged twice. That in turn will i.e. if you’re caching a select() - select the same field twice.
Rick James got me on the right track. I ended up having to chunk the results using pagination AND a nested query. Using LIMIT on even 1 chunk of 2000 records was timing out. This is the code I ended up with, which uses get_compiled_select('tblProgram') and then get('tblTrees O1'). Since I didn't use FALSE as the second argument to get_compiled_select, the query was cleared before the get() was run.
//grab the data in chunks, write it to CSV chunk by chunk
$offset=0;
$chunk=2000;
$i=10; //counter for the progress bar
$this->db->limit($chunk);
$this->db->select('tblTrees.id');
//nesting the limited query and then joining the other field later improved performance significantly
$query1=' ('.$this->db->get_compiled_select('tblProgram').') AS O2';
$this->db->join($query1, 'O1.id=O2.id');
$result=$this->db->get('tblTrees O1')->result_array();
$allResults=count($result);
$putHeaders=0;
$treePath=$this->config->item('temp_path')."$rand/trees.csv";
$tree_handle=fopen($treePath,'a');
//while select limit returns the limit
while (count($result)===$chunk) {
$highestID=max(array_column($result, 'id'));
//update progres bar with estimate
if ($i<90) {
$this->set_runStatus($qcRunId, $status = "processing", $progress = $i);
$i=$i+1;
}
//only get the fields the first time
foreach ($result as $row) {
if ($offset===0 && $putHeaders===0){
fputcsv($tree_handle, array_keys($row));
$putHeaders=1;
}
fputcsv($tree_handle, $row);
}
//get the next chunk
$offset=$offset+$chunk;
$this->db->reset_query();
$this->make_query($options);
$this->db->order_by('tblTrees.id', 'ASC');
$this->db->where('tblTrees.id >', $highestID);
$this->db->limit($chunk);
$this->db->select('tblTrees.id');
$query1=' ('.$this->db->get_compiled_select('tblProgram').') AS O2';
$this->db->join($query1, 'O1.id=O2.id');
$result=$this->db->get('tblTrees O1')->result_array();
$allResults=$allResults+count($result);
}
//write out last chunk
foreach ($result as $row) {
fputcsv($tree_handle, $row);
}
fclose($tree_handle);
return array('resultCount'=>$allResults);

How to retrieve and display a COUNT query result in PHP?

I'm a beginner who has problems with PHP :(
I have a PHP function which shows all the rows from the database table. Now I have to create paging to show only limited number of rows per one page.
I have a problem with retrieving a COUNT result from query. I want to create a condition where PHP & MySQL use LIMIT if number of rows is bigger than needed on one page. The following code:
$count = "SELECT COUNT(*) FROM articles";
$countq = $db->query($count);
$countrs = mysql_fetch_array($countq);
echo $countrs;
should display a number of rows. However, it does not. What am I doing wrong? I want to see a result to make sure that everything else will work fine. But I can't get it working.
Error: mysql_fetch_array() expects parameter 1 to be resource, object given
$db contains database connection information (server, user...) and is working
Use PDO for MySQL query.
$db = new PDO('mysql:host=#YOUR HOST#;dbname=#YOUR DB#;charset=utf8', '#YOUR LOGIN#', '#YOUR PASSWORD#');
$query = $db->query('SELECT COUNT(*) AS count FROM articles');
$countq = $query->fetch();
$query->closeCursor();
echo $countq['count'];
I hope this will help you
You will have to set the limit in the query like
$count = "SELECT COUNT(*) FROM articles LIMIT 5,10";
where 5 is the starting point and 10 is the total number of results you want.
You mention: $db but not what $db is? i mean is it a database object class? this will work directly if you are using the a database class, and if that's the case the class will also have functions which will allow you to query data without using mysql_fetch_array (actually mysqli_fetch_array).

Why does my code only return every second result in php mysql?

I have been writing some code which pulls entries from a MySQL database. These are numbers 1 to 38
However, it only returns every second number i.e. 2,4,6,8 instead of 1,2,3,4.
$result = mysql_query("select (caseID) FROM `case` order by caseID")
or die(mysql_error());
while(mysql_fetch_array( $result ))
{
$row = mysql_fetch_assoc($result);
$countName= $row['caseID'];
Print $countName;
}
I've tried various changes and reducing the code to the bare minimum. But nothing seems to work.
Calling mysql_fetch_array two times, thats why.
Try this
while($row=mysql_fetch_assoc( $result ))
{
$countName= $row['caseID'];
print $countName;
}
It is because you are calling mysql_fetch_array, which retrieves one result, and then you call mysql_fetch_assoc, which retrieves yet another result. That is then repeated until there are no more results left.
Or, in other words, you are fetching one result without using it, and then fetching another result which is then used, effectively jumping over every other result.
This should do the job:
while($row = mysql_fetch_assoc($result))
{
print $row['caseID'];
}
Also, take a look at the documentation. Turn your eyes to the big box that says "Warning" and has a stop sign in it.

How to get the number of results MySql would have returned without limit?

I have a table with a lot of data, so I retrieve it and display it one page at a time (my request is lengthy so there is no way I run it on the entire table).
But I would like to paginate the results, so I need to know what is the total number of elements in my table.
If I perform a COUNT(*) in the same request, I get the number of selected elements (in my case, 10).
If I perform a COUNT(*) on my table in a second request, the result might be wrong because of the where, join and having clauses in my main query.
What is the cleanest way to:
Retrieve the data
Know the maximum number of elements in my table for this specific request
One solution seems to be using the Mysql function FOUND_ROWS :
I tried this, as mysql_query performs one query at a time: (taken here)
$query = 'SELECT SQL_CALC_FOUND_ROWS * FROM Users';
$result = mysql_query($query);
// fetching the results ...
$query = 'SELECT FOUND_ROWS()';
$ result = mysql_query($query);
// debug
while ($row = mysql_fetch_row($result)) {
print_r($row);
}
And I got an array with 0 results:
Array ( [0] => 0 )
Whereas my query does returns results.
What is wrong with my approach ? Do you have a better solution ?
Set mysql.trace_mode to Off if it is On.
ini_set('mysql.trace_mode','Off'); may also work depending on your host configuration if you cannot edit my.cnf
If that doesn't make the code you posted above work, then you will need to run the query again without LIMIT and count it that way.
The code above works fine. I wasn't opening the connection correctly.
Output is :
Array ( [0] => 10976 )
I am still interested for an other way to do it, especially something that is not mysql dependent.

Echoing the sum of a table in PHP

I have 2 columns in a table called Points. The 2 columns are UserPoints and UserID.
I want to be able to echo the total amount of points a user has.
I've got something like this but I dont think its right.
$getTotalPoints = mysql_query("SELECT SUM(UserPoints) FROM `Points` WHERE `UserID` = '1'") or die(mysql_error());
$totalPoints = mysql_fetch_array($getTotalPoints);
When i echo the above statement by echoing "$totalPoints" i get "Array".
Anyone know the correct query to do this ?
You're getting Array because that's what's stored in $totalPoints. Look closely at your code and you'll see you used the mysql_fetch_array() function, which retrieves a row of results from the results set as an array. If you do var_dump() on $totalPoints you'll see the following:
Array
(
[0] => 12345
[SUM(UserPoints)] => 12345
)
The sum you're looking for is at index 0 or the column name, in this case SUM(UserPoints), so you can output it using echo $totalPoints[0] or echo $totalPoints['SUM(UserPoints)'].
Alternatively, you could use the mysql_result() function. I think this is more in-line with the behavior you were expecting. It fetches a single value from the row from the result set. So, instead of mysql_fetch_array() you'd wrote:
$totalPoints = mysql_result($result, 0);
For more information on mysql_result(), check out the PHP documentation for it.
As an aside, I would recommend not using mysql_* functions if you have the option. A newer interface like PDO, or at least mysqli, would be better. This will depend on your project of course... if you're working with a large legacy code base it may be difficult to change. But if you're starting out now, I think you'd benefit from the newer libraries. You can see my opinion and some guidance on transitioning extensions in this article I wrote.
Hope this helped... and good luck!
mysql_fetch_array fetches a result row as an associative array, a numeric array, or both. by default it creates both. all that you need is to echo $totalPoints[0];
or, if you rewrite you request as
$getTotalPoints = mysql_query("SELECT SUM(UserPoints) total FROM `Points`
WHERE `UserID` = '1'") or die(mysql_error());
$totalPoints = mysql_fetch_array($getTotalPoints);
echo $totalPoints['total'];
mysql_fetch_array returns an array. Therefore you need to treat $totalpoints as an array.
try adding this line to the end of your snippet:
echo $totalPoints[0];
There are several ways to retrieve data with the mysql functions I suggest reading about them in the php manual.
Here is mysql_fetch_array
The resultset row is an array with as many elements as you got in the SELECT.
In you case you only got 1 element (the sum).
So you should:
echo $totalPoints[0];
If you need to debug this kind of issues I recommend you to read about print_r function.

Categories