Igor's Blog

The MySQL SELECT statement syntax includes a LIMIT clause that can be used to restrict how much data is returned from the database. This is fantastic for pagination but in most cases you also want to know how many rows there are in total, which typically requires a second query. With MySQL there is a special option that can be passed to SELECT to do this calculation for you automatically.

First lets see what the documentation says about LIMIT...
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, with these exceptions:
* Within prepared statements, LIMIT parameters can be specified using ? placeholder markers.
* Within stored programs, LIMIT parameters can be specified using integer-valued routine parameters or local variables as of MySQL 5.5.6.

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)


This means I can write something like this (USERS is just a table from a project I implemented this in)...
 SQL
SELECT * FROM USERS LIMIT 0, 10;


That will return the first 10 rows from the USERS table. To get the next 10, I'd change the LIMIT clause to 'LIMIT 10, 10' and the next 10 would be 'LIMIT 20, 10', and so on.

If you specify an offset that is larger than the count of rows in your table, you simply don't get any data back (no error). However if you're building a user interface that paginates through results you want to know when to stop displaying the 'next' link (or link to the page number, etc) without having to rely on the database not returning any data.

Here's where that option I mentioned comes into play. The SQL_CALC_FOUND_ROWS option is required for the FOUND_ROWS() function to work. So you are in fact still having to execute two queries, but you're not having to run a COUNT() query on your data since that's already done by the database for you.

So the SQL changes to this...
 SQL
SELECT SQL_CALC_FOUND_ROWS * FROM USERS LIMIT 0, 10;

mysql_limit.png




Then immediately after running your query to fetch the data, you execute the following query:
 SQL
SELECT FOUND_ROWS();


That will return the total number of rows your original query would have returned if you didn't have the LIMIT clause.

Lets see an example - assume that the table USERS has 23 rows.
 Example
SQL run with LIMIT 0, 10: returns 10 rows.
Running FOUND_ROWS() returns 23;
SQL run with LIMIT 10, 10: returns 10 rows.
Running FOUND_ROWS() returns 23;
SQL run with LIMIT 20, 10: returns 3 rows.
Running FOUND_ROWS() returns 23;


So you can see that the LIMIT and offset do not have an effect on the count returned by FOUND_ROWS() - it will return the total count all the time exactly as if you were to do this:
 SQL
SELECT COUNT(*) FROM USERS;


What this means is if your'e doing pagination, you have to take the offset into account when calculating whether you have more data to paginate to or not. This caught me off guard at first!

If you're using PHP PDO, you can use this to get the result of FOUND_ROWS() ...
 PHP
// pdo is an instance of PDO
$statement = $pdo->query('SELECT FOUND_ROWS()');
$statement->fetchColumn();


P.S. The FOUND_ROWS() query must be run immediately after the SQL that fetches your data, if you run more SQL after that you will not get the right count back. I found the best way to do this is to use PDO and start a transaction for each of my statements, that way they're completely isolated from one another.

-i

comments powered by Disqus
Other posts you may like...
Programming, DIY, Games, Hacks, Tech and more.

Recent Blog Posts

Learn How to Add Disclaimer to All Outgoing Emails in Office 365

How to securely host your web site for free with Google Cloud and CloudFlare (part 3)

How to securely host your web site for free with Google Cloud and CloudFlare (part 2)

How to securely host your web site for free with Google Cloud and CloudFlare (part 1)

Beware of the subtle difference in date format strings between MySQL and SQLite

Postman reporting Unexpected 'N' error in response body

Adding extra shelves to the Ikea Detolf display cabinet

Posting array data from a web form to a Jersey REST service

How to avoid double encoding XML entities with Apache Commons StringEscapeUtils

Add your commonly used fonts to macOS Mail font drop down

Recent Galleries

Space Food - Chocolate Ice Cream with Chocolate Chips

Legeod Star Wars AT-DP kit

DIY spare parts computer build with a RAIDMAX Anura case

Fake 'Lepin' brand Lego packaging

Hardwood garden bench with clear resin void filler

Fixing a 3D printer extruder that stopped heating up

Easily increase disk space in a Lenovo Ideapad 100S 14" laptop with an M.2 SSD

Making a multi-piece 3D printed solder spool holder stand

DIY indoor apartment grow light wiring

Good Friday Electronics fun Easter Bunny LED PCB Kit IBEABU-01.0

My Other Web Sites

Igor and Elise's Travels
Riverside Expressway Cam
300 George St Blogumentary

My Online Tools

UUID to OID Converter
Guru JSON-RPC Tester
Extrudifier Object Designer
Travel ┬ÁBlog

Blogs and Friends

Matt Moores Blog
Georgi's FlatPress Guide
Perplexing Permutations
The Security Sleuth
Ilia Rogatchevski
Travelling Fairy

Blog Activity

Blog Activity
Please follow me for more great content!
     
Don't show this again