PHP MYSQL - Count & Average In Same Query - php

This may be very simple but I am trying to do a query that will return the average of the results but I also want it to count the number of rows it used to get the average. For example:
Row 1 = 5
Row 2 = 2
Row 3 = 9
Row 4 = 1
Average = 4.25
Count = 4
Is there a way to do this with one query apposed to two. When i used the avg function is always just returns one row so my count is 1 instead of 4. I need a query that will average but also tell me how many records it went through.
I am trying to avoid using two queries. Thank you for your help.

This is pretty basic and should have been discoverable via search.
SELECT COUNT(field) as `count`, AVG(field) as `average` FROM table_name

In the terms you have stated - if you aren't GROUPing or things like that - you'd just write
SELECT COUNT(col) AS cnt, AVG(col) AS avg FROM tbl;
and you ought to have no problems. You get one row, with the fields cnt and col containing what you need.
The problem you're having is probably due to the use of mysql_num_rows to get the count, which is not correct.
forgot to add: or to the fact that you did not supplied your whole problem.

You can use multiple aggregate functions in a single query:
SELECT COUNT(*), AVG(field) FROM mytable

SELECT COUNT(*), AVG(YourColumn)
FROM YourTable

Related

MYSQL from the 20th row to the last row [duplicate]

I would like to construct a query that displays all the results in a table, but is offset by 5 from the start of the table. As far as I can tell, MySQL's LIMIT requires a limit as well as an offset. Is there any way to do this?
From the MySQL Manual on LIMIT:
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;
As you mentioned it LIMIT is required, so you need to use the biggest limit possible, which is 18446744073709551615 (maximum of unsigned BIGINT)
SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5
As noted in other answers, MySQL suggests using 18446744073709551615 as the number of records in the limit, but consider this: What would you do if you got 18,446,744,073,709,551,615 records back? In fact, what would you do if you got 1,000,000,000 records?
Maybe you do want more than one billion records, but my point is that there is some limit on the number you want, and it is less than 18 quintillion. For the sake of stability, optimization, and possibly usability, I would suggest putting some meaningful limit on the query. This would also reduce confusion for anyone who has never seen that magical looking number, and have the added benefit of communicating at least how many records you are willing to handle at once.
If you really must get all 18 quintillion records from your database, maybe what you really want is to grab them in increments of 100 million and loop 184 billion times.
Another approach would be to select an autoimcremented column and then filter it using HAVING.
SET #a := 0;
select #a:=#a + 1 AS counter, table.* FROM table
HAVING counter > 4
But I would probably stick with the high limit approach.
As others mentioned, from the MySQL manual. In order to achieve that, you can use the maximum value of an unsigned big int, that is this awful number (18446744073709551615). But to make it a little bit less messy you can the tilde "~" bitwise operator.
LIMIT 95, ~0
it works as a bitwise negation. The result of "~0" is 18446744073709551615.
You can use a MySQL statement with LIMIT:
START TRANSACTION;
SET #my_offset = 5;
SET #rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING #rows, #my_offset;
COMMIT;
Tested in MySQL 5.5.44. Thus, we can avoid the insertion of the number 18446744073709551615.
note: the transaction makes sure that the variable #rows is in agreement to the table considered in the execution of statement.
I ran into a very similar issue when practicing LC#1321, in which I have to select all the dates but the first 6 dates are skipped.
I achieved this in MySQL with the help of ROW_NUMBER() window function and subquery. For example, the following query returns all the results with the first five rows skipped:
SELECT
fieldname1,
fieldname2
FROM(
SELECT
*,
ROW_NUMBER() OVER() row_num
FROM
mytable
) tmp
WHERE
row_num > 5;
You may need to add some more logics in the subquery, especially in OVER() to fit your need. In addition, RANK()/DENSE_RANK() window functions may be used instead of ROW_NUMBER() depending on your real offset logic.
Reference:
MySQL 8.0 Reference Manual - ROW_NUMBER()
Just today I was reading about the best way to get huge amounts of data (more than a million rows) from a mysql table. One way is, as suggested, using LIMIT x,y where x is the offset and y the last row you want returned. However, as I found out, it isn't the most efficient way to do so. If you have an autoincrement column, you can as easily use a SELECT statement with a WHERE clause saying from which record you'd like to start.
For example,
SELECT * FROM table_name WHERE id > x;
It seems that mysql gets all results when you use LIMIT and then only shows you the records that fit in the offset: not the best for performance.
Source: Answer to this question MySQL Forums. Just take note, the question is about 6 years old.
I know that this is old but I didnt see a similar response so this is the solution I would use.
First, I would execute a count query on the table to see how many records exist. This query is fast and normally the execution time is negligible. Something like:
SELECT COUNT(*) FROM table_name;
Then I would build my query using the result I got from count as my limit (since that is the maximum number of rows the table could possibly return). Something like:
SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;
Or possibly something like:
SELECT * FROM table_name LIMIT desired_offset, count_result;
Of course, if necessary, you could subtract desired_offset from count_result to get an actual, accurate value to supply as the limit. Passing the "18446744073709551610" value just doesnt make sense if I can actually determine an appropriate limit to provide.
WHERE .... AND id > <YOUROFFSET>
id can be any autoincremented or unique numerical column you have...

count all items in table mysql plus get record

Hi I have this situation:
$query = $db->query('SELECT COUNT(*),* FROM memberFileReports');
$data = $query->fetch(PDO::FETCH_ASSOC);
print_r($data);
its not working ? any idea why and how to Count and get all items at the same time, and what if I want to Count (*) and then next Select will have Limit 0,5?
Is this what you're looking for?
SELECT * , CONCAT('', (SELECT COUNT(*) FROM memberFileReports)) AS total
FROM memberFileReports LIMIT 0,5
EDIT 1: Note that the 'total' will be a string
EDIT 2: As I understand , you want to get the total rows in the table, but only select 5 of them (as example)
EDIT 3: caps... and misspell
Use this
SELECT * , COUNT(*) FROM memberFileReports Group by column_id
Instead of this
SELECT COUNT(*),* FROM memberFileReports
EDIT:
try this
$data = $query->fetchAll();
instead of
$data = $query->fetch(PDO::FETCH_ASSOC);
I know this post is a little late but i figured i would tell you, the reason why you only get one row back is because you are using an aggregate function "COUNT()". that function makes it so the result is returned in one row. the way to show stuff in more than one row is to use a "GROUP BY" in your select statement and it will group the data by the condition you tell it to.
example... suppose we had an example table with 3 users..
one has 10 interactions
one 3
and one 33:
SELECT
e.UserID,
COUNT(e.interactions) as num_interactions
FROM example e
GROUP BY e.UserID;
that would show the number of interactions a user has made in the dummy example table.
OUTPUT:
UserID num_interactions
1 3
2 10
3 33
without the GROUP BY the aggregate would make the output look like this:
UserID num_interactions
1 46
just for future reference :)

select rows as well as a total count in one query in mysql

suppose I have a table t and table t has 15000 entries
suppose the query
SELECT * FROM t WHERE t.nid <1000
returns 1000 rows
but then I only want the first 10 rows so I do a LIMIT
SELECT * FROM t WHERE t.nid <1000 LIMIT 10
is it possible to construct a single query in which in addition to returning the 10 rows information with the LIMIT clause above, it also returns the total count of the rows that satisfy the conditions set in the WHERE clause, hence in addition to returning the 10 rows above, it also returns 1000 since there are a total of 1000 rows satisfying the WHERE clause...and have both returned in a single query
Preferred solution
First of all, the found_rows() function is not portable (it is a MySQL extension) and is going to be removed. As user #Zveddochka pointed out, it has already been deprecated in MySQL 8.0.17.
But more importantly, it turns out that if you use proper indexing, then running two queries is actually faster. The SQL_CALC_FOUND_ROWS directive is achieved through a "virtual scan" that incurs an additional recovery cost. When the query is not indexed, then this cost would be the same of a COUNT(), and therefore running two queries will cost double - i.e., using SQL_CALC_FOUND_ROWS will make things run 50% faster.
But what happens when the query is properly indexed? The guys at Percona checked it out. And it turns out that not only the COUNT() is blazing fast since it only accesses metadata and indexes, and the query without SQL_CALC_FOUND_ROWS is faster because it doesn't incur any additional cost; the cost of the two queries combined is less than the cost of the enhanced single query:
Results with SQL_CALC_FOUND_ROWS are following: for each b value it
takes 20-100 sec to execute uncached and 2-5 sec after warmup. Such
difference could be explained by the I/O which required for this query
– mysql accesses all 10k rows this query could produce without LIMIT
clause.
The results are following: it takes 0.01-0.11 sec to run this query
first time and 0.00-0.02 sec for all consecutive runs.
So, as we can see, total time for SELECT+COUNT (0.00-0.15 sec) is much
less than execution time for original query (2-100 sec). Let’s take a
look at EXPLAINs...
So, what to do?
// Run two queries ensuring they satisfy exactly the same conditions
$field1 = "Field1, Field2, blah blah blah";
$field2 = "COUNT(*) AS rows";
$where = "Field5 = 'X' AND Field6 = 'Y' AND blah blah";
$cntQuery = "SELECT {$field2} FROM {$joins} WHERE {$where}";
$rowQuery = "SELECT {$field1} FROM {$joins} WHERE {$where} LIMIT {$limit}";
Now the first query returns the count, the second query returns the actual data.
Old answer (useful just for non-indexed tables)
Don't do this. If you find out this section of the answer works for you better than the section above, it's almost certainly a signal that something else is not optimal in your setup - most likely you're not using the indexes properly, or you need to update your MySQL server, or run an analyze/optimize of the database to update cardinality statistics.
You can, but I think it would be a performance killer.
Your best option would be to use the SQL_CALC_FOUND_ROWS MySQL extension and issue a second query to recover the full number of rows using FOUND_ROWS().
SELECT SQL_CALC_FOUND_ROWS * FROM t WHERE t.nid <1000 LIMIT 10;
SELECT FOUND_ROWS();
See e.g http://www.arraystudio.com/as-workshop/mysql-get-total-number-of-rows-when-using-limit.html
Or you could simply run the full query without LIMIT clause, and retrieve only the first ten rows. Then you can use one query as you wanted, and also get the row count through mysql_num_rows(). This is not ideal, but also not so catastrophic for most queries.
If you do this last, though, be very careful to close the query and free its resources: I have found out that retrieving less than the full resultset and forgetting to free the rs handle is one outstanding cause of "metadata locking".
You can try SQL_CALC_FOUND_ROWS, which can get a count of total records without running the statement again.
SELECT SQL_CALC_FOUND_ROWS * FROM t WHERE t.nid <1000 LIMIT 10; -- get records
SELECT FOUND_ROWS(); -- get count
Reference: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html
"is it possible to construct a single query in which in addition to returning the 10 rows information with the LIMIT clause above, it also returns the total count of the rows that satisfy the conditions set in the WHERE clause"
Yes, it is possible to do both in single query, by using windowed function i.e. COUNT(*) OVER()(MySQL 8.0+):
SELECT t.*, COUNT(*) OVER() AS cnt
FROM t
WHERE t.nid <1000
LIMIT 10;
db<>fiddle demo
Sidenote:
LIMIT without explicit ORDER BY is non-deterministic. It could return different results between multiple runs.
There are many things that need discussing.
A LIMIT without an ORDER BY is somewhat unpredictable, hence somewhat meaningless.
But if you add an ORDER BY, it may need to find all the rows, sort them then deliver only the 10 you want.
Or, the ORDER BY may be handled adequately by an INDEX.
Your particular query, if turned into 2 queries (as needed after 8.0.17), would be
SELECT * FROM t WHERE t.nid < 1000 LIMIT 10;
SELECT COUNT(*) FROM t WHERE t.nid < 1000;
Note that each of those would benefit from INDEX(nid). The first would pick 10 items from the index's BTree, then look them up in the data's BTree -- only 10 rows touched in each. The second would scan the INDEX until it hits 1000, and not touch the data BTree.
If you add an ORDER BY as advised, then, the first query:
SELECT * FROM t WHERE t.nid < 1000 ORDER BY t.nid LIMIT 10;
will work identically as above. But
SELECT * FROM t WHERE t.nid < 1000 ORDER BY t.abcd LIMIT 10;
will need to scan lots of rows, and be quite slow. And probably use a temp table and filesort. (Check EXPLAIN for details.) INDEX(nid, abcd) would help, but only a little.
And there are other variants, such as when the index can be "covering".
What is the goal of having "one query"?
Speed? -- as discussed above, there are other factors that are more pertinent.
Consistency? -- You may need a transaction to avoid, for example, getting N rows from the first query and a smaller number from the COUNT.
BEGIN;
SELECT * ...
SELECT COUNT(*) ...
COMMIT;
Single command? -- Consider a stored procedure that combines the 2 statements. Or
SELECT * FROM t WHERE t.nid < 1000 LIMIT 10
UNION ALL
SELECT COUNT(*) FROM t WHERE t.nid < 1000;
but that gets tricky because the number of columns is different, so some kludge would be needed to make the second query have the same number of columns. Another variant involves GROUP BY WITH ROLLUP. (But it may be even harder to fabricate.)
Lukasz's Answer looks promising. However, it gives an extra column (which might be good) and its performance needs to be tested. If you are on 8.0 and their answer works well for you, accept that Answer.
Count(*) time complexity is O(1), so you can use a subquery
SELECT *, (SELECT COUNT(*) FROM t WHERE t.nid <1000) AS cnt
FROM t
WHERE t.nid <1000
LIMIT 10
Sounds like you want FOUND_ROWS()
SELECT SQL_CALC_FOUND_ROWS * FROM t WHERE t.nid <1000 LIMIT 10;
SELECT FOUND_ROWS();

Optimize MySQL query order in the results using GROUP BY and count

I have the following query:
SELECT vBrowser,iconBrowser, count(iconBrowser) as 'N'
FROM user_ip_tmp WHERE code='9m9g9tsv2y'
GROUP BY iconBrowser
ORDER BY N DESC
LIMIT 40
And this works properly. But the delirious cause query took a long time.
Showing rows 0 - 17 ( 18 total, Query took 4.4189 sec)
Things that are in WHERE statement, should be indexed.
Try to use EXPLAIN statement before your SELECT to see what and how is used to retrief your requested results.
And if the column code is not an unique value, i would recommend to put it in some other table, where it is unique. Then build the query using JOIN though the FOREIGN KEY.

Apply a limit of 10 after taking distinct records in mysql

In a MySQL table, I would like to take 10 records with DISTINCT values.
I am using Zend Framework.
$select = $this->getAdapter()->select()
->from('table', 'column')->group('column')
->limit(10, 0);
This is the query generated by the above code.
SELECT table.column FROM
table GROUP BY column LIMIT 10
What happens here is that MySQL is taking 10 records first and then applying the group by. So finally, I am getting only 7 records.
How to apply DISTINCT first and then take 10 records from it?
Test that SQL against a table -- MySQL applies the limit last, so doesn't do what you're saying. eg test against
a0 a1
1 1
2 1
3 2
4 2
and do select A.a1 from A group by a1 limit 2. You should see 1, 2, not 1, 1.
[I wanted to say this as a 'comment' rather than an 'answer', but couldn't]
I'm not 100% sure what you are trying to do.
But if i am reading it correct you need 10 records with a certain criteria and then apply the group. not the other way around.
Can't you use WHERE in this case?
SELECT table.column FROM table WHERE "criteria" GROUP BY column LIMIT 10
Regards
Mike
This may help you (I didn't test it but so I'm not sure it's working)
SELECT DISTINCT column FROM table LIMIT 10
If it's not working, you may use a temporary table (like (SELECT column FROM table) TEMP), which will select the distinct elements, then a query which will select the first ten results into this table.
Hope this'll help :)
In ZF, You should use distinct() method into Your query chain :
$select = $this->getAdapter()->select()
->distinct()
->from('table', 'column')
->limit(10, 0);
SELECT DISTINCT column
FROM table
LIMIT 10
GROUP BY column
Not sure how to get it into classes though...

Categories