AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

03 Sorting and limiting / Lesson 3 of 5

LIMIT and OFFSET — taking a slice of the result

13 min · +10 XP · 2 exercises · 5 questions

Read the text13 min
Exercises0/2
Quiz5 q

Quick answer

What do LIMIT and OFFSET do in MySQL?

LIMIT n returns at most n rows of a query's result, and OFFSET m skips the first m rows before counting. They run last, after WHERE and ORDER BY, so ORDER BY price LIMIT 3 gives the three cheapest rows. MySQL also accepts LIMIT m, n, offset first. Without ORDER BY, which rows you get is undefined.

Most of the time you do not want every row a query can produce. A home page shows the five newest posts, a dashboard the ten biggest customers, an API the first page of results, and an interview question asks for "the highest salary". LIMIT cuts a result down to its first rows, and OFFSET skips some rows before the cut starts. They are small clauses, but they come with a rule people forget — they mean nothing without ORDER BY — and with more dialect differences than almost anything else in SQL. This lesson covers both clauses, MySQL's comma form, where they sit in the processing order, and the TOP and FETCH FIRST spellings you will meet in other databases.

LIMIT

SELECT id, customer, total
FROM orders
ORDER BY total DESC
LIMIT 3;
idcustomertotal
14Ravi4200
3Anita3900
9Sam2750

LIMIT 3 keeps at most three rows. "At most": if the query only produces two rows, you get two; if it produces none, you get none. LIMIT 0 is legal and returns no rows at all — tools sometimes use it to learn a query's column names without fetching data.

LIMIT is the very last step of the query. In the logical order — FROM, WHERE, SELECT, ORDER BY, LIMIT — the rows are filtered, computed and sorted first, and only then is the first slice taken. So WHERE decides which rows are candidates, ORDER BY decides which of them are "first", and LIMIT decides how many of those you keep.

Always sort before you limit

LIMIT takes the first rows of the result's order. Without ORDER BY there is no defined order, so:

SELECT id, customer FROM orders LIMIT 3;   -- some three orders

returns some three orders. Today they may be the first three inserted; after a delete, an update or a new index, they may be three others. This is the single most common LIMIT bug in code review and the reason an interviewer frowns at a "top" query without a sort. And because ties are unordered too, a limited result is only reproducible when the sort is unique: ORDER BY total DESC, id. With two orders tied at the cut-off, ORDER BY total DESC LIMIT 3 may return either one.

OFFSET

OFFSET m skips the first m rows of the sorted result, then LIMIT counts from there:

SELECT id, customer, total
FROM orders
ORDER BY total DESC, id
LIMIT 3 OFFSET 3;      -- rows 4, 5 and 6
LIMIT keeps a slice of the sorted rows; OFFSET says where it starts
SELECT id, customer, total FROM orders ORDER BY total DESC, id LIMIT 3 OFFSET …

The 8 orders as storage hands them back. A LIMIT on this would take some three rows — whichever came first today.

0:01 / 0:17Step 1 of 6
Transcript · 6 steps

Offsets count from zero: OFFSET 0 skips nothing, OFFSET 3 starts at the fourth row. An offset past the end is not an error — the result is simply empty. In MySQL an OFFSET must come with a LIMIT; to skip rows and keep "all the rest", the documented trick is a huge limit such as LIMIT 18446744073709551615 OFFSET 10. That need is rare.

MySQL's comma form

MySQL also accepts two numbers separated by a comma:

LIMIT 3, 5     -- skip 3, then take 5   (the same as LIMIT 5 OFFSET 3)

The comma form puts the offset first and the count second, the opposite of the reading order of LIMIT 5 OFFSET 3. It is everywhere in older PHP tutorials and an easy point for a trick question: LIMIT 10, 20 returns twenty rows, starting with the eleventh. SQLite accepts it with the same meaning; PostgreSQL does not. Prefer LIMIT … OFFSET … in anything you write — the words say which number is which.

One more MySQL detail: the numbers must be literal non-negative integers or ? placeholders in a prepared statement. LIMIT 2 + 1 and LIMIT (SELECT …) are syntax errors in MySQL, though some other engines accept expressions there.

The other spellings

LIMIT is not in the SQL standard, and every database family has its own way to say it. You will see all of them in interviews:

DatabaseFirst 5 rowsRows 11–15
MySQL, SQLiteLIMIT 5LIMIT 5 OFFSET 10
PostgreSQLLIMIT 5 or FETCH FIRST 5 ROWS ONLYOFFSET 10 LIMIT 5
SQL ServerSELECT TOP (5) …OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY
Oracle 12c+FETCH FIRST 5 ROWS ONLYOFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY
Older OracleWHERE ROWNUM <= 5 (in a subquery)nested ROWNUM subqueries

The standard form, OFFSET … ROWS FETCH FIRST|NEXT … ROWS ONLY, also offers FETCH FIRST 3 ROWS WITH TIES, which keeps any extra rows tied with the last one — PostgreSQL 13+, Oracle and SQL Server's TOP (3) WITH TIES support it, MySQL does not. In MySQL, "top three including ties" needs a subquery or a window function, both later in the course. The Oracle ROWNUM trap is worth knowing: ROWNUM is assigned before ORDER BY, so WHERE ROWNUM <= 5 ORDER BY salary DESC sorts five arbitrary rows instead of finding the top five.

LIMIT with WHERE and DISTINCT

Because LIMIT is last, it applies to whatever the rest of the query produced:

-- The three cheapest products that are in stock
SELECT name, price
FROM products
WHERE stock > 0
ORDER BY price, id
LIMIT 3;

-- The three highest distinct prices
SELECT DISTINCT price
FROM products
ORDER BY price DESC
LIMIT 3;

In the second query, duplicates are removed before the limit: if three products cost 900, the result is still three different prices. That ordering — distinct, then sort, then limit — is the heart of the classic "Nth highest salary" question in the top-N lesson.

LIMIT is not a performance switch by itself

LIMIT 10 can make a query cheap: if an index already delivers rows in the ORDER BY order, the database reads ten rows and stops. Without such an index it must find and sort every matching row before it can know which ten come first, so ORDER BY + LIMIT 10 on a million unindexed rows still sorts a million rows. And OFFSET 100000 reads and throws away a hundred thousand rows before returning anything. The next lesson, on pagination, is about what to do instead.

Before you move on

  • LIMIT n keeps at most n rows; OFFSET m skips m first; both run last.
  • Always pair them with an ORDER BY whose last key is unique.
  • MySQL's LIMIT m, n is offset first, count second.
  • SQL Server uses TOP and OFFSET … FETCH; the standard and Oracle use FETCH FIRST n ROWS ONLY.
  • DISTINCT happens before LIMIT.

Common questions

What is the difference between LIMIT 5, 10 and LIMIT 5 OFFSET 10?

They are different slices. MySQL's comma form puts the offset first, so LIMIT 5, 10 skips 5 rows and returns the next 10. LIMIT 5 OFFSET 10 skips 10 rows and returns the next 5. The OFFSET form is clearer and is also what PostgreSQL and SQLite accept.

What is the SQL Server equivalent of LIMIT?

SQL Server uses SELECT TOP (n) … for a plain limit and ORDER BY … OFFSET m ROWS FETCH NEXT n ROWS ONLY for a slice. The SQL standard's form, FETCH FIRST n ROWS ONLY, also works in PostgreSQL, Oracle 12c and later, and Db2. MySQL supports only LIMIT.

Why use ORDER BY with LIMIT?

Because LIMIT takes the first rows of whatever order the result has, and without ORDER BY that order is undefined. SELECT * FROM orders LIMIT 5 returns some five rows, not the newest or the cheapest, and they can differ between runs. Sort first to say which rows count as first.

What happens if OFFSET is larger than the number of rows?

The query returns no rows and no error. LIMIT 10 OFFSET 500 on a 120-row result is simply empty, which is how an application knows it has paged past the end.

Mark as readSign in to keep your place.

SQL LIMIT and OFFSET in MySQL: TOP and FETCH FIRST Compared

MySQL LIMIT returns only the first rows of a sorted result and OFFSET skips some before them. LIMIT m, n, why it needs ORDER BY, and TOP and FETCH FIRST.

  • Course: SQL study plan
  • Module: Sorting and limiting
  • Kind: Lesson
  • Reading time: 13 min
  • Runtime: MySQL 8 syntax on SQLite 3.49

What do LIMIT and OFFSET do in MySQL?

LIMIT n returns at most n rows of a query's result, and OFFSET m skips the first m rows before counting. They run last, after WHERE and ORDER BY, so ORDER BY price LIMIT 3 gives the three cheapest rows. MySQL also accepts LIMIT m, n, offset first. Without ORDER BY, which rows you get is undefined.

Lesson

Most of the time you do not want every row a query can produce. A home page shows the five newest posts, a dashboard the ten biggest customers, an API the first page of results, and an interview question asks for "the highest salary". LIMIT cuts a result down to its first rows, and OFFSET skips some rows before the cut starts. They are small clauses, but they come with a rule people forget — they mean nothing without ORDER BY — and with more dialect differences than almost anything else in SQL. This lesson covers both clauses, MySQL's comma form, where they sit in the processing order, and the TOP and FETCH FIRST spellings you will meet in other databases.

LIMIT

SELECT id, customer, total
FROM orders
ORDER BY total DESC
LIMIT 3;
idcustomertotal
14Ravi4200
3Anita3900
9Sam2750

LIMIT 3 keeps at most three rows. "At most": if the query only produces two rows, you get two; if it produces none, you get none. LIMIT 0 is legal and returns no rows at all — tools sometimes use it to learn a query's column names without fetching data.

LIMIT is the very last step of the query. In the logical order — FROM, WHERE, SELECT, ORDER BY, LIMIT — the rows are filtered, computed and sorted first, and only then is the first slice taken. So WHERE decides which rows are candidates, ORDER BY decides which of them are "first", and LIMIT decides how many of those you keep.

Always sort before you limit

LIMIT takes the first rows of the result's order. Without ORDER BY there is no defined order, so:

SELECT id, customer FROM orders LIMIT 3;   -- some three orders

returns some three orders. Today they may be the first three inserted; after a delete, an update or a new index, they may be three others. This is the single most common LIMIT bug in code review and the reason an interviewer frowns at a "top" query without a sort. And because ties are unordered too, a limited result is only reproducible when the sort is unique: ORDER BY total DESC, id. With two orders tied at the cut-off, ORDER BY total DESC LIMIT 3 may return either one.

OFFSET

OFFSET m skips the first m rows of the sorted result, then LIMIT counts from there:

SELECT id, customer, total
FROM orders
ORDER BY total DESC, id
LIMIT 3 OFFSET 3;      -- rows 4, 5 and 6
… LIMIT 3 OFFSET 9ordersidcustomertotal2Dev15003Anita39005Meera21007Tara9009Sam275011Kiran180012Omar65014Ravi4200no rows — an empty result, not an error12345678
LIMIT keeps a slice of the sorted rows; OFFSET says where it starts. Example: SELECT id, customer, total FROM orders ORDER BY total DESC, id LIMIT 3 OFFSET …
  1. The 8 orders as storage hands them back. A LIMIT on this would take some three rows — whichever came first today.
  2. ORDER BY total DESC, id runs before LIMIT and decides which rows are first. id breaks any tie, so the order is the same on every run.
  3. LIMIT 3 is the very last step: it keeps the first three sorted rows — the top three orders, led by Ravi at 4200.
  4. OFFSET 3 skips three rows first, counting from zero, and LIMIT counts from there: rows 4 to 6, the second page.
  5. OFFSET 6 leaves only 2 rows. LIMIT means at most, so the third page is short rather than padded or an error.
  6. An offset past the end, OFFSET 9 on 8 rows, skips everything: the result is the column headings and no rows.

Offsets count from zero: OFFSET 0 skips nothing, OFFSET 3 starts at the fourth row. An offset past the end is not an error — the result is simply empty. In MySQL an OFFSET must come with a LIMIT; to skip rows and keep "all the rest", the documented trick is a huge limit such as LIMIT 18446744073709551615 OFFSET 10. That need is rare.

MySQL's comma form

MySQL also accepts two numbers separated by a comma:

LIMIT 3, 5     -- skip 3, then take 5   (the same as LIMIT 5 OFFSET 3)

The comma form puts the offset first and the count second, the opposite of the reading order of LIMIT 5 OFFSET 3. It is everywhere in older PHP tutorials and an easy point for a trick question: LIMIT 10, 20 returns twenty rows, starting with the eleventh. SQLite accepts it with the same meaning; PostgreSQL does not. Prefer LIMIT … OFFSET … in anything you write — the words say which number is which.

One more MySQL detail: the numbers must be literal non-negative integers or ? placeholders in a prepared statement. LIMIT 2 + 1 and LIMIT (SELECT …) are syntax errors in MySQL, though some other engines accept expressions there.

The other spellings

LIMIT is not in the SQL standard, and every database family has its own way to say it. You will see all of them in interviews:

DatabaseFirst 5 rowsRows 11–15
MySQL, SQLiteLIMIT 5LIMIT 5 OFFSET 10
PostgreSQLLIMIT 5 or FETCH FIRST 5 ROWS ONLYOFFSET 10 LIMIT 5
SQL ServerSELECT TOP (5) …OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY
Oracle 12c+FETCH FIRST 5 ROWS ONLYOFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY
Older OracleWHERE ROWNUM <= 5 (in a subquery)nested ROWNUM subqueries

The standard form, OFFSET … ROWS FETCH FIRST|NEXT … ROWS ONLY, also offers FETCH FIRST 3 ROWS WITH TIES, which keeps any extra rows tied with the last one — PostgreSQL 13+, Oracle and SQL Server's TOP (3) WITH TIES support it, MySQL does not. In MySQL, "top three including ties" needs a subquery or a window function, both later in the course. The Oracle ROWNUM trap is worth knowing: ROWNUM is assigned before ORDER BY, so WHERE ROWNUM <= 5 ORDER BY salary DESC sorts five arbitrary rows instead of finding the top five.

LIMIT with WHERE and DISTINCT

Because LIMIT is last, it applies to whatever the rest of the query produced:

-- The three cheapest products that are in stock
SELECT name, price
FROM products
WHERE stock > 0
ORDER BY price, id
LIMIT 3;

-- The three highest distinct prices
SELECT DISTINCT price
FROM products
ORDER BY price DESC
LIMIT 3;

In the second query, duplicates are removed before the limit: if three products cost 900, the result is still three different prices. That ordering — distinct, then sort, then limit — is the heart of the classic "Nth highest salary" question in the top-N lesson.

LIMIT is not a performance switch by itself

LIMIT 10 can make a query cheap: if an index already delivers rows in the ORDER BY order, the database reads ten rows and stops. Without such an index it must find and sort every matching row before it can know which ten come first, so ORDER BY + LIMIT 10 on a million unindexed rows still sorts a million rows. And OFFSET 100000 reads and throws away a hundred thousand rows before returning anything. The next lesson, on pagination, is about what to do instead.

Before you move on

  • LIMIT n keeps at most n rows; OFFSET m skips m first; both run last.
  • Always pair them with an ORDER BY whose last key is unique.
  • MySQL's LIMIT m, n is offset first, count second.
  • SQL Server uses TOP and OFFSET … FETCH; the standard and Oracle use FETCH FIRST n ROWS ONLY.
  • DISTINCT happens before LIMIT.

Common questions

What is the difference between LIMIT 5, 10 and LIMIT 5 OFFSET 10?

They are different slices. MySQL's comma form puts the offset first, so LIMIT 5, 10 skips 5 rows and returns the next 10. LIMIT 5 OFFSET 10 skips 10 rows and returns the next 5. The OFFSET form is clearer and is also what PostgreSQL and SQLite accept.

What is the SQL Server equivalent of LIMIT?

SQL Server uses SELECT TOP (n) … for a plain limit and ORDER BY … OFFSET m ROWS FETCH NEXT n ROWS ONLY for a slice. The SQL standard's form, FETCH FIRST n ROWS ONLY, also works in PostgreSQL, Oracle 12c and later, and Db2. MySQL supports only LIMIT.

Why use ORDER BY with LIMIT?

Because LIMIT takes the first rows of whatever order the result has, and without ORDER BY that order is undefined. SELECT * FROM orders LIMIT 5 returns some five rows, not the newest or the cheapest, and they can differ between runs. Sort first to say which rows count as first.

What happens if OFFSET is larger than the number of rows?

The query returns no rows and no error. LIMIT 10 OFFSET 500 on a 120-row result is simply empty, which is how an application knows it has paged past the end.

Exercises

The three latest orders

The orders table:

idcustomerplaced_ontotal
1Anita2024-03-01500
2Ravi2024-03-041200
3Sam2024-03-0290
4Lena2024-03-04300
5Omar2024-02-2775

Return the three most recent orders as id, customer, placed_on, newest first. Orders placed on the same day: the higher id first. If there are fewer than three orders, return them all.

id | customer | placed_on
4 | Lena | 2024-03-04
2 | Ravi | 2024-03-04
3 | Sam | 2024-03-02

Rows four to six

The products table:

idnameprice
1pen10
2ruler25
3glue30
4tape30
5folder45
6marker15
7scissors80
8stapler120

Sorted by price ascending, then id, return only the 4th, 5th and 6th rows as id, name, price. With fewer rows, return whatever exists in those positions.

id | name | price
3 | glue | 30
4 | tape | 30
5 | folder | 45

In this module: Sorting and limiting

← Sorting on several keys, ties and custom orders · Pagination — offset pages and keyset pages →