Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk4 min

ROW_NUMBER vs RANK vs DENSE_RANK: What Top-N Queries Return When Values Tie

ROW_NUMBER limits individual rows, while RANK and DENSE_RANK preserve ties in different ways. See which function fits your Top-N query and why tied results may exceed N.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose among ROW_NUMBER(), RANK() and DENSE_RANK() based on what “Top-N” means for your query. ROW_NUMBER() <= N returns at most N rows per group, but can split a tie at the cutoff. RANK() <= N keeps ties at competition positions up to N and may return more than N rows. DENSE_RANK() <= N returns the first N distinct ordering values, also potentially more than N rows.

How the three functions treat ties

All three are window functions that assign numbers according to an ordering. Their key difference is whether tied rows share a number and whether the next number skips ahead.

As an Amazon Associate I earn from qualifying purchases.

Function What tied rows get What happens next Meaning of filtering to <= N
ROW_NUMBER() A distinct number for every row. The order among ties can be nondeterministic unless the window ordering resolves it. No gaps: each row receives the next number. At most N rows per partition; a tie at the cutoff can be split.
RANK() The same rank for peers. Gaps account for the number of rows sharing the previous rank. Competition positions through N, including ties at the cutoff; may return more than N rows.
DENSE_RANK() The same rank for peers. No gaps: the next distinct value advances the rank by one. The first N distinct ordering values; may return more than N rows.

For example, with metric values 100, 90, 90, 80, the results are:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Metric ROW_NUMBER() RANK() DENSE_RANK()
100 1 1 1
90 2 or 3 2 2
90 2 or 3 2 2
80 4 4 3

The two ROW_NUMBER() results for 90 can swap unless the ordering includes a stable tie-breaker. Filtering to three illustrates the different rules: ROW_NUMBER() <= 3 returns three rows, with the tie split only if the cutoff falls inside its peer group. RANK() <= 3 returns 100 and both 90s; there is no rank 3 because the next competition rank is 4. DENSE_RANK() <= 3 returns all four rows because there are three distinct metric values.

Choose the function that matches the result you need

Use ROW_NUMBER for a fixed row limit

Choose ROW_NUMBER() when you need no more than N individual rows per group, or need to select one row from each group. If reproducibility matters, add a stable unique key after the business sort key. Otherwise, rows tied on the sort key may receive different row numbers across executions or plans.

Use RANK to preserve competition positions

Choose RANK() when equal values should share a place and the next place should reflect how many rows tied. With values 100, 90, 90, 80, the ranks are 1, 2, 2, 4. Filtering through rank N can return more than N rows when the Nth position is tied.

Use DENSE_RANK for the first N distinct values

Choose DENSE_RANK() when you mean the first N distinct metric values or value groups. Ties share a rank, but the next distinct value advances by one without a gap. The result may include many rows for any of those N values.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Write a per-group Top-N query

This SQL pattern selects up to three rows in each category, sorting by metric and then by a unique item identifier:

WITH ranked AS (
  SELECT
    category,
    item_id,
    metric,
    ROW_NUMBER() OVER (
      PARTITION BY category
      ORDER BY metric DESC, item_id
    ) AS rn
  FROM items
)
SELECT category, item_id, metric
FROM ranked
WHERE rn <= 3
ORDER BY category, metric DESC, item_id;

PARTITION BY category restarts numbering for each category. The window’s ORDER BY defines the numbering or ranking order; the final query’s ORDER BY controls how results are displayed. Filtering on the window result is done in the outer query.

To keep every item tied at the third competition position, use RANK() ordered by metric DESC and filter its result to <= 3. To return the three highest distinct metric values, use DENSE_RANK() with the same metric ordering. Keep the peer definition aligned with the requirement: adding a unique ID to the RANK() or DENSE_RANK() window ordering makes otherwise tied metrics separate peers. A final display sort can still include that ID.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Check your database’s window-function rules

The tie and gap behavior is consistent across the cited documentation, but syntax and nondeterminism details vary by database. Use the reference for the target engine and version before relying on a production query.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • SQL Server / Transact-SQL: Microsoft’s documentation requires a window ORDER BY for ROW_NUMBER and RANK; its references describe shared ranks and gaps for RANK, and no gaps for DENSE_RANK. See Microsoft’s ROW_NUMBER reference, RANK (Transact-SQL) and DENSE_RANK (Transact-SQL).
  • Google BigQuery / GoogleSQL: ROW_NUMBER does not require ORDER BY, but without it row numbering is nondeterministic. Ordering among peers is also nondeterministic. BigQuery documents RANK as advancing by the number of peers in the previous rank and DENSE_RANK as advancing by one. See GoogleSQL numbering functions.
  • PostgreSQL 17: The official reference describes rank as having gaps and dense_rank as having none; window functions depend on the window’s sort ordering. See PostgreSQL 17 window functions.

These references cover SQL Server, BigQuery and PostgreSQL 17; they are not a complete survey of every SQL dialect.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.