Free demoJob-oriented courses at Debugshala, Old Palasia, Indore. Freshers, non-IT and year-gap welcome.Book a free demo +91-8982385539

SQL ORDER BY, LIMIT and DISTINCT: Sort and Trim Results

Lesson 6 of 29 · 10 min · Updated 13 Nov 2026

Learn SQL ORDER BY, LIMIT, OFFSET and DISTINCT with runnable examples: multi-column sorts, NULL ordering, top-N lists and page-by-page results.

At the end of March, Malwa Mart's owner pins a "Top 3 orders of the month" sheet on the staff noticeboard at the Rajwada branch. To make it, a clerk sorts all the bills from largest to smallest, copies the first three, and stops.

The owner also wants a list of every payment method customers used. The clerk does not write "UPI" forty times. She writes each method once.

Sorting the bills is ORDER BY. Copying only the first three is LIMIT. Writing each payment method once is DISTINCT. These three tools turn a raw pile of rows into something a person can read in five seconds.

ORDER BY sorts the rows of a result, LIMIT restricts how many rows are returned, and DISTINCT removes duplicate rows, all applied after the WHERE filter has run.

In the previous article you learned to pick rows with SQL SELECT and WHERE. This one shapes those rows into ranked, trimmed, de-duplicated answers.

How does ORDER BY sort results?

ORDER BY goes near the end of the query and names the column to sort on. ASC sorts from smallest to largest and is the default. DESC reverses it.

SQL
SELECT order_id, order_date, amount
FROM orders
ORDER BY amount DESC;

Numbers sort by value, dates in ISO text sort by calendar order, and text sorts alphabetically according to the database's collation, its rules for comparing characters.

Sorting by several columns

When the first column has ties, the second column decides. This is how you get a stable, predictable order.

SQL
SELECT order_id, order_date, amount
FROM orders
ORDER BY order_date DESC, amount DESC;

Read it as "newest date first, and within the same date, biggest amount first". Each column gets its own direction; DESC does not carry over to the next column.

Python
import sqlite3

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE orders (order_id INT, customer_id INT, store_id INT, order_date TEXT, amount INT, payment_mode TEXT)")
con.executemany("INSERT INTO orders VALUES (?, ?, ?, ?, ?, ?)", [
    (101, 1, 1, "2026-03-01", 1040, "UPI"), (102, 2, 2, "2026-03-01", 330, "Cash"),
    (103, 1, 1, "2026-03-03", 275, "UPI"), (104, 3, 3, "2026-03-04", 180, "Card"),
    (105, 4, 2, "2026-03-05", 680, "UPI"), (106, 2, 4, "2026-03-07", 120, "Cash"),
    (107, 5, 3, "2026-03-08", 1560, "Card"), (108, 6, 1, "2026-03-08", 220, "UPI"),
    (109, 4, 4, "2026-03-10", 340, None), (110, 1, 2, "2026-03-12", 465, "Cash")])

print("By amount, largest first:")
print([r for r in con.execute("SELECT order_id, amount FROM orders ORDER BY amount DESC")][:4])
print("By date (newest first), then amount (largest first):")
for row in con.execute("SELECT order_date, order_id, amount FROM orders ORDER BY order_date DESC, amount DESC"):
    print(row)

Orders 107 and 108 share 8 March, and 101 and 102 share 1 March. In both pairs the larger amount comes first because of the second sort column.

Sorting by an expression or alias

You can sort by a calculated value, and in every major database you can sort by a SELECT alias, because ORDER BY runs after SELECT.

SQL
SELECT product_name, price, price * 1.05 AS price_with_tax
FROM products
ORDER BY price_with_tax DESC;

You may also see ORDER BY 2, meaning "the second column in SELECT". It works, but it breaks silently when someone reorders the columns, so prefer names.

Quick check

A table has 10 orders across 4 stores and 3 payment modes. What decides how many rows SELECT DISTINCT store_id, payment_mode returns?

Where do NULLs go when you sort?

Databases disagree on this, and it matters in reports. Order 109 has no payment mode.

Database NULLs in ASC order NULLs in DESC order Supports NULLS FIRST / LAST?
SQLite First Last Yes (3.30+)
MySQL 8 First Last No
PostgreSQL 16 Last First Yes
SQL Server First Last No
Oracle Last First Yes

When the position matters, say it explicitly with NULLS LAST. In MySQL, use the trick ORDER BY payment_mode IS NULL, payment_mode, which sorts the 0s (not null) before the 1s (null).

Python
import sqlite3

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE orders (order_id INT, payment_mode TEXT)")
con.executemany("INSERT INTO orders VALUES (?, ?)",
                [(104, "Card"), (106, "Cash"), (108, "UPI"), (109, None)])

for clause in ["payment_mode", "payment_mode NULLS LAST", "payment_mode IS NULL, payment_mode"]:
    rows = con.execute(f"SELECT order_id, payment_mode FROM orders ORDER BY {clause}").fetchall()
    print(f"ORDER BY {clause:36} {rows}")

How do LIMIT and OFFSET work?

LIMIT n returns at most n rows. Combined with ORDER BY, it answers every "top N" question.

SQL
SELECT order_id, amount
FROM orders
ORDER BY amount DESC
LIMIT 3;

OFFSET k skips the first k rows before LIMIT counts. This is how websites show results page by page. For page number p with n rows per page, the offset is (p - 1) * n.

SQL LIMIT and OFFSET pagination: ten sorted orders split into pages of three using OFFSET 0, 3 and 6

With a page size of 3, page 1 uses OFFSET 0, page 2 uses OFFSET 3 and page 3 uses OFFSET 6. Sorting first keeps every page consistent.

Python
import sqlite3

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE orders (order_id INT, amount INT)")
con.executemany("INSERT INTO orders VALUES (?, ?)", [
    (101, 1040), (102, 330), (103, 275), (104, 180), (105, 680),
    (106, 120), (107, 1560), (108, 220), (109, 340), (110, 465)])

top3 = con.execute("SELECT order_id, amount FROM orders ORDER BY amount DESC LIMIT 3").fetchall()
print("Top 3 orders:", top3)

page_size = 3
for page in range(1, 5):
    offset = (page - 1) * page_size
    rows = con.execute("SELECT order_id FROM orders ORDER BY amount DESC LIMIT ? OFFSET ?",
                       (page_size, offset)).fetchall()
    print(f"Page {page} (OFFSET {offset}):", [r[0] for r in rows])

The fourth page holds just one order, because ten rows do not divide evenly into threes. Passing the numbers as placeholders keeps the query safe when the page number comes from a web request.

LIMIT in other databases

LIMIT is not part of the SQL standard, so syntax varies.

Database First 3 rows Skip 6, then take 3
SQLite, PostgreSQL, MySQL LIMIT 3 LIMIT 3 OFFSET 6
MySQL (also) LIMIT 3 LIMIT 6, 3
SQL Server SELECT TOP 3 ... OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY
Standard SQL, PostgreSQL, Oracle 12c+ FETCH FIRST 3 ROWS ONLY OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY

Quick check

Which query returns the second page of orders, five per page, largest first?

How does DISTINCT remove duplicates?

DISTINCT comes right after SELECT and removes rows that are exact repeats of another row in the result.

SQL
SELECT DISTINCT payment_mode FROM orders;

With several columns, DISTINCT looks at the combination. SELECT DISTINCT store_id, payment_mode keeps one row for each store-and-method pair, so a store that took both UPI and Cash appears twice. NULLs count as equal to each other for DISTINCT, so all missing values collapse into one row.

Python
import sqlite3

con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE orders (order_id INT, store_id INT, payment_mode TEXT)")
con.executemany("INSERT INTO orders VALUES (?, ?, ?)", [
    (101, 1, "UPI"), (102, 2, "Cash"), (103, 1, "UPI"), (104, 3, "Card"), (105, 2, "UPI"),
    (106, 4, "Cash"), (107, 3, "Card"), (108, 1, "UPI"), (109, 4, None), (110, 2, "Cash")])

print("All rows:", con.execute("SELECT COUNT(*) FROM orders").fetchone()[0])
print("Payment modes:", con.execute("SELECT DISTINCT payment_mode FROM orders ORDER BY payment_mode").fetchall())
pairs = con.execute("SELECT DISTINCT store_id, payment_mode FROM orders ORDER BY store_id, payment_mode").fetchall()
print(len(pairs), "store-mode pairs:", pairs)

Ten orders collapse into four payment modes, including None, and six store-mode pairs. To count unique values instead of listing them, use COUNT(DISTINCT payment_mode), covered in SQL aggregate functions.

The order these clauses run in

You write SELECT DISTINCT ... ORDER BY ... LIMIT, but the database applies them in a fixed logical sequence. Knowing it explains why LIMIT without ORDER BY gives random-looking results.

SQL logical order with ORDER BY, LIMIT and DISTINCT: FROM, WHERE, SELECT, DISTINCT, ORDER BY, then LIMIT and OFFSET

Rows are filtered first, then columns are chosen and de-duplicated, then sorted, and only then trimmed.

  1. FROM picks the table.
  2. WHERE filters rows.
  3. SELECT computes the output columns and aliases.
  4. DISTINCT removes duplicate result rows.
  5. ORDER BY sorts what is left.
  6. LIMIT / OFFSET keeps the requested slice.

GROUP BY and HAVING slot in between WHERE and SELECT; you will meet them after aggregates. One consequence: in PostgreSQL, when you use DISTINCT, every ORDER BY expression must also appear in the SELECT list.

Common mistakes with ORDER BY, LIMIT and DISTINCT

  • LIMIT without ORDER BY. The database may return any rows, and the answer can change between runs.
  • Forgetting the tie-breaker. If two orders have the same amount, page 1 and page 2 can swap them. Add a unique column like order_id as the last sort key.
  • Assuming DESC applies to every column. ORDER BY store_id, amount DESC sorts stores ascending.
  • Using DISTINCT to hide a bad join. If a join creates duplicates, fix the join; DISTINCT only masks it.
  • Sorting text with mixed case. SQLite's default collation puts Zebra before apple. Use ORDER BY LOWER(name) or SQLite's COLLATE NOCASE.

Want feedback on queries like these from a trainer? The analyst training programme at Debugshala runs offline classes in Indore with a free demo session.

Key takeaways

  • ORDER BY col [ASC|DESC] sorts; extra columns break ties, each with its own direction.
  • NULL placement differs by database; use NULLS FIRST or NULLS LAST where supported.
  • LIMIT n OFFSET k gives top-N lists and pages; always pair it with ORDER BY.
  • DISTINCT removes duplicate rows across all selected columns.
  • Next, see these clauses combined in SQL for data analysis, then learn aggregate functions.
Take the free SQL quiz10 quick questions with explanations. No sign-up needed, and you can come back to this lesson after.

FAQ

What is the default sort order in SQL ORDER BY?

The default is ascending (ASC): smallest numbers, earliest dates and A-to-Z text first. You only need to write ASC for readability. Write DESC after a column to reverse it, and repeat it for each column you want descending, because the direction does not carry over.

What is the difference between LIMIT and TOP in SQL?

They do the same job with different syntax. LIMIT goes at the end of the query and is used by MySQL, PostgreSQL and SQLite. TOP goes right after SELECT and is used by SQL Server. The SQL standard form, FETCH FIRST n ROWS ONLY, works in PostgreSQL, Oracle and SQL Server.

Is DISTINCT slower than GROUP BY?

For simply removing duplicates, most databases plan DISTINCT and GROUP BY the same way, so speed is similar. Use DISTINCT when you only want unique rows, and GROUP BY when you also need totals or counts per group. Either can be slow on huge tables without suitable indexes.

Why does my query return rows in a different order each time?

Without ORDER BY, the database returns rows in whatever order is fastest, which can change after inserts, deletes or a new query plan. Results only have a guaranteed order when you specify one. Add ORDER BY with a unique column as the final tie-breaker.

Can I learn SQL with a trainer in Indore?

Yes. Debugshala, at Old Palasia in Indore, runs offline Data Analytics classes in English and Hindi, with a free demo class before you pay. Between sessions, keep your logic sharp with quizzes on Debugshala Test.

From the team behind this site

Go further with the Data Analytics Course at Debugshala

These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.

  • Offline classes at Old Palasia, Indore
  • Free demo class before you pay
  • Non-IT, fresher and year-gap friendly
  • Placement assistance

700+ students placed · 200+ hiring partners · 4.9★ Google rating

SQL SELECT and WHERE: Filter Rows with Clear ExamplesSQL for Data Analysis: SELECT, GROUP BY and JOIN with Examples