skip to content

How do you write row limiting in standard SQL instead of LIMIT and OFFSET?

level: middleimportance: should knowfreq 45%

answer

  1. LIMIT is not the ISO spelling
  2. two keywords: one skips, one fetches
  3. it goes after ORDER BY
  4. FIRST and NEXT mean the same thing

basics

~20 s

Standard SQL writes the slice as OFFSET n ROWS FETCH NEXT m ROWS ONLY, placed after ORDER BY. LIMIT is a widely implemented extension, not the ISO spelling; FIRST and NEXT, and ROW and ROWS, are interchangeable.

solid answer

~50 s

The ISO form is the **row-limiting clause**, written after `ORDER BY`: ```sql SELECT id, total FROM orders ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; ``` `OFFSET n ROWS` skips, `FETCH NEXT m ROWS ONLY` caps — exactly the meaning of `LIMIT 10 OFFSET 20`. Both parts are optional: `FETCH FIRST 10 ROWS ONLY` alone is a plain top-10, and the `OFFSET` clause may stand alone where the engine allows it. `FIRST` and `NEXT` are pure synonyms — `NEXT` reads better after an `OFFSET` — and `ROW`/`ROWS` are interchangeable, so `FETCH FIRST ROW ONLY` means one row. Support is uneven despite the word "standard": PostgreSQL, Oracle 12c and later, and SQL Server 2012 and later accept it, while MySQL and SQLite accept only `LIMIT`/`OFFSET`. Check your target engine rather than assuming portability in either direction.

code

sql · 11 lines
sql
-- Standard SQL:2008 row-limiting clause: rows 21..30
SELECT id, total
FROM orders
ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;

-- The same slice in the LIMIT/OFFSET spelling
SELECT id, total
FROM orders
ORDER BY id
LIMIT 10 OFFSET 20;

go deeper

for a junior

Know that LIMIT is not the only spelling and be able to read OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY as the same slice when you meet it in someone else's SQL.

for a middle

Write the clause from memory with correct placement after ORDER BY, and explain that both halves are optional and that FIRST/NEXT and ROW/ROWS are synonyms.

for a senior

Show judgment about which spelling to use where — one known engine versus generated multi-dialect SQL — and note that the standard clause still guarantees nothing without a total ordering.

for a principal

Treat the limiting clause as the dialect seam in otherwise portable SQL: isolate it behind a renderer or an abstraction so an engine migration does not become a query-by-query rewrite.

## Two spellings for one idea Every mainstream engine can return a contiguous slice of an ordered result, but they did not agree on syntax first and standardise later. Two families exist: ```sql -- widely implemented extension SELECT ... ORDER BY id LIMIT 10 OFFSET 20; -- ISO row-limiting clause SELECT ... ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; ``` Both mean: sort by `id`, discard 20 rows, return at most the next 10. The standard clause arrived in SQL:2008; `LIMIT` predates it by many years and is not part of ISO SQL, which is why it is called an extension even though it is the form most developers type. ## Anatomy of the standard clause The clause has two independent, optional parts, and they must appear in this order after `ORDER BY`: 1. **`OFFSET <count> ROWS`** — skip `<count>` rows of the ordered result. 2. **`FETCH { FIRST | NEXT } [<count>] { ROW | ROWS } ONLY`** — return at most `<count>` of the rows that remain. The keyword pairs are synonyms, present purely for readability: - `FIRST` and `NEXT` are equivalent. `FETCH FIRST` reads naturally on its own; `FETCH NEXT` reads naturally after an `OFFSET`. Neither continues from a previous statement — there is no hidden cursor state, and every execution starts from the beginning of a freshly computed result. - `ROW` and `ROWS` are equivalent, so you can write `OFFSET 1 ROW` without grammatical pain. - The count may be omitted, in which case it defaults to one: `FETCH FIRST ROW ONLY` returns a single row. `ONLY` is the terminator that says "stop at exactly that many rows". Its alternative, `WITH TIES`, changes the semantics by also returning rows that tie with the last one on the `ORDER BY` key — a different clause with a different meaning. ## Using either half alone ```sql -- top-10, no skipping SELECT customer_id, SUM(total) AS lifetime FROM orders GROUP BY customer_id ORDER BY lifetime DESC, customer_id FETCH FIRST 10 ROWS ONLY; -- skip the header rows of a staging load, keep the rest SELECT * FROM raw_import ORDER BY line_no OFFSET 3 ROWS; ``` The second form — an offset with no fetch — is valid standard SQL, but engines differ on whether they accept a skip with no row-count limit at all, so it is the least portable shape of the four. ## Ordering is still your responsibility Neither spelling creates an order. `FETCH FIRST 10 ROWS ONLY` on an unordered query returns ten arbitrary rows, exactly as `LIMIT 10` does, and a sort key with duplicates leaves the page boundary undefined in both. Some engines go further and *require* an `ORDER BY` before the standard clause; others allow it without. Write the total ordering — leading key plus a unique tie-breaker — regardless of which engine you are on, because the determinism you want comes from the ordering, not from the limiting syntax. ## Which one should you actually write? - If the SQL lives inside one application against one known engine, use whichever form that engine documents; `LIMIT` is shorter and universally understood by readers. - If the SQL must run against several engines — a portable schema tool, an analytics query shipped to customers, generated SQL — prefer the standard clause and verify each target, because "standard" here does not mean "universally accepted". Two very common engines (MySQL and SQLite) implement only `LIMIT`/`OFFSET`, while PostgreSQL, Oracle 12c and later, and SQL Server 2012 and later implement the standard clause; PostgreSQL accepts both. - If you are generating SQL programmatically, keep the limiting clause behind a per-dialect renderer rather than string-formatting one spelling everywhere. It is the single most dialect-divergent piece of an otherwise portable `SELECT`. ## What an interviewer is checking The question is rarely about memorising syntax. It checks that you know `LIMIT` is not standard SQL, that you can name the ISO form and place it after `ORDER BY`, and that you understand the clause is optional in both halves. A candidate who adds "and it still needs a total ORDER BY to be meaningful" has answered the question behind the question.

  • Is FETCH NEXT 10 ROWS ONLY different from FETCH FIRST 10 ROWS ONLY?
    No — `FIRST` and `NEXT` are interchangeable synonyms with identical meaning. `NEXT` simply reads better after an `OFFSET` clause. Neither keeps cursor state between statements: every execution recomputes the result and counts from its beginning.
  • What does FETCH FIRST ROW ONLY, with no number, return?
    One row. The count is optional and defaults to one, and `ROW`/`ROWS` are interchangeable spellings. It is the standard way to write a single-row probe, equivalent to `LIMIT 1`.
  • Does the standard clause make a query portable across engines?
    Not by itself. Despite being ISO SQL, it is not universally implemented — MySQL and SQLite accept only `LIMIT`/`OFFSET`, and some engines demand an `ORDER BY` before it. For generated or multi-engine SQL, render the limiting clause per dialect rather than assuming one form travels.

saying these in an interview costs you the question

  • Believes LIMIT is part of the SQL standard
  • Thinks FETCH NEXT continues from the previous statement
  • Puts the row-limiting clause before ORDER BY
  • Assumes the ISO clause works on every engine
  • Says ONLY and WITH TIES are just style choices

context