In SELECT ... ORDER BY id LIMIT 10 OFFSET 20, what do LIMIT and OFFSET each control?
answer
- two numbers, two different jobs
- one skips rows, one caps rows
- skipping happens before capping
- third page of ten-row pages
basics
~20 sOFFSET 20 discards the first 20 rows of the ordered result; LIMIT 10 then returns at most the next 10 — rows 21 through 30. OFFSET applies first, and LIMIT counts only rows that survive the skip.
solid answer
~40 s`OFFSET` says how many rows of the ordered result to throw away before returning anything; `LIMIT` caps how many rows are returned after that skip. So `ORDER BY id LIMIT 10 OFFSET 20` yields rows 21–30 of the ordering — the third page if pages are ten rows wide, with `OFFSET = (page - 1) * page_size`. Two things are worth stating explicitly. First, `LIMIT` is an upper bound, not a promise: if only four rows remain after the skip, you get four, and if the offset runs past the end you get an empty result rather than an error. Second, both clauses operate on the *ordered* result, so without a deterministic `ORDER BY` the phrase "rows 21 through 30" is meaningless — the engine may hand back any rows at all.
go deeper
Be able to state the slice out loud: skip OFFSET rows, then return at most LIMIT rows. Know the page formula OFFSET = (page - 1) * size and that page 1 uses OFFSET 0.
Explain that limiting is the last step of the query, that LIMIT is an upper bound rather than a guarantee, and that an offset past the end yields an empty result rather than an error.
Show that you treat a page as meaningful only under a total ordering, and that you add a unique tie-breaker column to the sort keys before anyone reports rows jumping between pages.
Frame row limiting as part of the list-endpoint contract: what the API promises about page stability, whether an empty page is a valid response, and whether offsets belong in the contract at all.
## The two numbers do different jobs Row limiting takes a result that the rest of the query has already computed and returns a contiguous slice of it. Two independent numbers describe that slice: - **OFFSET n** — skip the first `n` rows of the result and do not return them. - **LIMIT m** — of whatever remains, return at most `m` rows. ```sql SELECT id, total FROM orders ORDER BY id LIMIT 10 OFFSET 20; -- rows 21..30 of the id ordering ``` The skip always happens first, regardless of the order the two keywords are written in. `LIMIT 10 OFFSET 20` and `OFFSET 20 LIMIT 10` mean the same thing where both spellings are accepted; the count after `LIMIT` is never "the first ten, then skip twenty". ## Where limiting sits relative to the rest of the query Limiting is the very last thing that happens. Rows are produced by `FROM`, filtered by `WHERE`, grouped and filtered again by `GROUP BY`/`HAVING`, projected by the select list, sorted by `ORDER BY` — and only then sliced. That matters in practice: `LIMIT` cannot make a filter cheaper by "stopping early" from the author's point of view, and a `LIMIT` on the outer query does not restrict what a subquery inside it computes. If you want the ten highest totals, `ORDER BY total DESC LIMIT 10` gives them; `LIMIT 10` followed by a sort would be a different (and meaningless) query, which is why the standard fixes the order of these clauses. ## Page arithmetic The common use is paging a list. With one-based page numbers and a fixed page size: ```sql -- page 4, 25 rows per page SELECT id, title FROM articles ORDER BY published_at DESC, id DESC LIMIT 25 OFFSET 75; -- (4 - 1) * 25 ``` Off-by-one bugs here are almost always the page-number base: page 1 must use `OFFSET 0`, not `OFFSET 25`. Note the second sort key — see below. ## What LIMIT does not promise **It is an upper bound.** `LIMIT 10` returns ten rows *or fewer*. A query whose result holds 24 rows, asked for `LIMIT 10 OFFSET 20`, returns four. Application code that assumes a full page and infers "there is no next page" from a short page is usually right, but code that assumes exactly `m` rows is wrong. **Overshooting is not an error.** `OFFSET 1000` against a 30-row result returns the empty set. There is no exception, no warning, and no clamping to the last page — an empty page is what a caller past the end sees. **It does not create an order.** `LIMIT` slices whatever order the engine produced. Without `ORDER BY`, no order is defined, so "the first ten rows" is whatever the plan happened to emit. Even *with* `ORDER BY`, if the sort key is not unique the rows tied on that key may come back in any order, so the boundary between page 3 and page 4 can move between requests. The fix is to make the ordering total by appending a unique column, typically the primary key: ```sql ORDER BY published_at DESC, id DESC ``` **The offset is a position, not an anchor.** It counts rows in a result recomputed from scratch on every request, so it says nothing about *which* rows you saw last time. ## Spelling and portability `LIMIT ... OFFSET ...` is the widely implemented spelling but is not the ISO standard one. Standard SQL writes the same slice as `OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY`, placed after `ORDER BY`. Engines differ on which forms they accept and on whether `OFFSET` may appear with no row-count limit at all, so if a query has to move between engines, check the target's documentation rather than assuming. ## Reading a query quickly When you see `ORDER BY <keys> LIMIT m OFFSET n`, read it as: sort by the keys, drop `n` rows, keep the next `m`. Then ask the two follow-up questions an interviewer is waiting for — is the ordering total, and does the caller need the same rows to stay on the same page while data changes underneath? The first is answered by adding a unique tie-breaker; the second is a property of offset-based paging itself.
- What comes back if the OFFSET is larger than the number of rows the query produces?An empty result set — zero rows, no error and no warning. Nothing clamps the offset to the last page, so a caller who asks for page 500 of a 3-page list simply gets nothing. Application code has to treat an empty page as a normal outcome rather than a failure.
- Does LIMIT 10 guarantee that exactly ten rows come back?No. It is an upper bound. If only four rows remain after the offset is applied, four rows are returned. Code that assumes a full page will break at the end of a list; code that infers "this was the last page" from a short page is generally safe.
- How do page number and page size map onto LIMIT and OFFSET?With one-based page numbers, `LIMIT = page_size` and `OFFSET = (page - 1) * page_size`. Page 1 therefore uses `OFFSET 0`. The classic bug is a zero/one-based mismatch between the API's page parameter and the arithmetic, which silently skips or repeats an entire page.
saying these in an interview costs you the question
- Says LIMIT 10 OFFSET 20 returns rows 11 through 20
- Thinks LIMIT is applied first and OFFSET afterwards
- Expects an error when OFFSET runs past the end
- Assumes exactly LIMIT rows always come back
- Believes pages are stable without any ORDER BY