Row Function in SQL: Syntax, Practical Examples, and Performance Tips
By Mukesh Kumar
Updated on Mar 05, 2025 | 19 min read | 1.5k views
Share:
For working professionals
For fresh graduates
More
By Mukesh Kumar
Updated on Mar 05, 2025 | 19 min read | 1.5k views
Share:
Table of Contents
Row function in SQL structures query results by assigning row numbers, ranks, and partitions. It enhances data organization, making sorting, filtering, and pagination more efficient. Businesses use these functions to optimize reporting, analytics, and query performance.
This guide covers row numbers in SQL with syntax, examples, and performance tips for ranking, pagination, and optimization. Let’s start.
A row function in SQL is a built-in function that assigns a unique number or rank to each row in a result set based on specified criteria. These functions improve data organization, ranking, and filtering, making them essential for reporting, trend analysis, and pagination.
They enable structured queries for tasks like ranking sales performance, numbering customer transactions, or segmenting large datasets for efficient retrieval.
Row functions are critical when building ranking systems, such as leaderboards or sales performance reports. Functions like ROW_NUMBER(), RANK(), and DENSE_RANK() allow you to assign sequential numbers, handle duplicates, and determine relative positions within partitions.
These functions are widely used in applications requiring ordered results, such as leaderboards, sales rankings, and paginated reports.
The general syntax for row functions in SQL follows this structure:
SELECT column_name,
ROW_NUMBER() OVER (PARTITION BY column_name ORDER BY column_name) AS row_num
FROM table_name;
Example and Output
Sample employees Table:
employee_id |
department |
salary |
101 |
Sales |
60000 |
102 |
Sales |
75000 |
103 |
Sales |
50000 |
104 |
IT |
90000 |
105 |
IT |
85000 |
Query Execution
SELECT employee_id, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num
FROM employees;
Output:
employee_id |
department |
salary |
row_num |
102 |
Sales |
75000 |
1 |
101 |
Sales |
60000 |
2 |
103 |
Sales |
50000 |
3 |
104 |
IT |
90000 |
1 |
105 |
IT |
85000 |
2 |
Database Variations
Different SQL databases support row functions with slight variations:
Also Read: List of Operators In SQL [With Examples]
Understanding database variations ensures that SQL queries run as expected across different platforms and helps optimize their performance. Along with row functions, arguments in SQL refine function behavior and enhance flexibility. Next, we’ll explore how arguments influence queries for better data manipulation.
Arguments in row functions help control how data is processed and ranked in SQL queries. They define sorting rules and grouping criteria, making results more structured and meaningful. The two most commonly used arguments in row functions are:
Using ORDER BY and PARTITION BY correctly ensures accurate row numbering and ranking in SQL queries. To apply these arguments effectively, you need to understand the syntax of row functions and how they structure query results.
Row functions use a structured syntax to define ranking and ordering within a dataset. Below is the general syntax:
SELECT column_name,
ROW_NUMBER() OVER (PARTITION BY column_name ORDER BY column_name) AS row_num
FROM table_name;
Example and Output
Sample employees Table:
employee_id |
department |
salary |
101 |
Sales |
60000 |
102 |
Sales |
75000 |
103 |
Sales |
50000 |
104 |
IT |
90000 |
105 |
IT |
85000 |
Query Execution
SELECT employee_id, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num
FROM employees;
Output:
employee_id |
department |
salary |
row_num |
102 |
Sales |
75000 |
1 |
101 |
Sales |
60000 |
2 |
103 |
Sales |
50000 |
3 |
104 |
IT |
90000 |
1 |
105 |
IT |
85000 |
2 |
Also Read: What Is Programming Language? Syntax, Top Languages, Examples
Understanding the syntax and output of row functions is essential for writing efficient queries, but their implementation can vary across database systems. Different SQL databases support row functions with unique behaviors and limitations, affecting how they handle ranking and ordering.
Row functions are widely used across various database systems, but each has specific implementations:
Also Read: Most Asked Oracle Interview Questions and Answers – For Freshers and Experienced
To effectively use these functions, you need a practical approach that applies them in real-world scenarios. Let’s walk through a step-by-step example to understand how row functions work in SQL queries.
To demonstrate row functions in SQL, we'll use a practical example with an employees table. This dataset will be referenced throughout the article to illustrate different SQL operations.
Sample employees Table
employee_id |
name |
department |
salary |
101 |
Alice |
Sales |
60000 |
102 |
Bob |
Sales |
75000 |
103 |
Charlie |
Sales |
50000 |
104 |
David |
IT |
90000 |
105 |
Emma |
IT |
85000 |
Step-by-Step Implementation:
1. Assigning Row Numbers Using ROW_NUMBER()
SELECT employee_id, name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num
FROM employees;
Output
employee_id |
name |
department |
salary |
row_num |
102 |
Bob |
Sales |
75000 |
1 |
101 |
Alice |
Sales |
60000 |
2 |
103 |
Charlie |
Sales |
50000 |
3 |
104 |
David |
IT |
90000 |
1 |
105 |
Emma |
IT |
85000 |
2 |
Here, ROW_NUMBER()assigns a unique number to each row within departments, ordered by descending salary.
In SQL Server, creating a table with the right schema ensures efficient data management and query execution. Let’s explore how to set up a table before implementing row functions.
In SQL Server, the CREATE TABLE statement is used to define a new table with specific columns, data types, and constraints. Below is the general syntax:
CREATE TABLE table_name (
column1 datatype constraints,
column2 datatype constraints,
column3 datatype constraints,
...
);
For example, creating an employees table:
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50),
salary DECIMAL(10,2)
);
Once a table is created in SQL Server, you can apply row functions to rank and number records efficiently. However, not all row functions behave the same way. Understanding the differences between ROW_NUMBER(), RANK(), and DENSE_RANK() is essential for choosing the right function for your use case.
SQL provides multiple row functions to assign rankings based on specific conditions. Below is a comparison of ROW_NUMBER(), RANK(), and DENSE_RANK().
Function |
Behavior |
Handles Duplicates? |
Gaps in Ranking? |
ROW_NUMBER() |
Assigns a unique number to each row |
No |
Yes |
RANK() |
Assigns the same rank to duplicates; next rank is skipped |
Yes |
Yes |
DENSE_RANK() |
Assigns the same rank to duplicates; next rank follows sequentially |
Yes |
No |
Example Data (employees Table):
employee_id |
name |
department |
salary |
101 |
Alice |
Sales |
60000 |
102 |
Bob |
Sales |
75000 |
103 |
Charlie |
Sales |
75000 |
104 |
David |
IT |
90000 |
105 |
Emma |
IT |
85000 |
The following query applies ROW_NUMBER(), RANK(), and DENSE_RANK() to rank employees based on salary.
Query for ROW_NUMBER(), RANK(), and DENSE_RANK()
SELECT employee_id, name, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_number,
RANK() OVER (ORDER BY salary DESC) AS rank_num,
DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank
FROM employees;
The output highlights how these functions rank employees differently when handling duplicate salaries.
Output
employee_id |
name |
salary |
row_number |
rank_num |
dense_rank |
104 |
David |
90000 |
1 |
1 |
1 |
105 |
Emma |
85000 |
2 |
2 |
2 |
102 |
Bob |
75000 |
3 |
3 |
3 |
103 |
Charlie |
75000 |
4 |
3 |
3 |
101 |
Alice |
60000 |
5 |
5 |
4 |
Beyond ranking, SQL also provides the NTILE() function to distribute rows into equal-sized groups, which is particularly useful for percentile rankings and segmentation.
The NTILE(n) function assigns each row to one of n groups, making it useful for evenly distributing data. Below is an example dividing employees into three groups based on salary.
Syntax:
SELECT employee_id, name, salary,
NTILE(3) OVER (ORDER BY salary DESC) AS ntile_group
FROM employees;
The output below shows how employees are assigned to different percentile groups.
Output (Dividing into 3 Groups):
employee_id |
name |
salary |
ntile_group |
104 |
David |
90000 |
1 |
105 |
Emma |
85000 |
1 |
102 |
Bob |
75000 |
2 |
103 |
Charlie |
75000 |
2 |
101 |
Alice |
60000 |
3 |
Ranking and grouping data efficiently is essential, but row functions also play a crucial role in pagination, especially for handling large datasets. Pagination helps break results into smaller, manageable pages, improving performance and user experience in applications like web-based dashboards and reports.
Pagination in SQL is commonly implemented using ROW_NUMBER() along with the OFFSET and FETCH NEXT clauses. This approach allows retrieving specific subsets of data, such as showing 10 records per page in a web application.
SQL Query for Pagination (Displaying Page 2 with 2 Records per Page):
WITH EmployeePagination AS (
SELECT employee_id, name, department, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees
)
SELECT employee_id, name, department, salary
FROM EmployeePagination
WHERE row_num BETWEEN 3 AND 4;
Output (Page 2 with 2 Records per Page):
employee_id |
name |
department |
salary |
102 |
Bob |
Sales |
75000 |
103 |
Charlie |
Sales |
75000 |
Here, ROW_NUMBER() assigns sequential numbers, and BETWEEN filters for page 2. While useful in SQL Server and PostgreSQL, databases without window functions can use LIMIT and OFFSET for pagination.
Many SQL databases, including MySQL and PostgreSQL, support LIMIT and OFFSET for pagination. This approach is simpler and performs well in smaller datasets.
Pagination with LIMIT/OFFSET (Displaying Page 2 with 2 Records per Page)
SELECT employee_id, name, department, salary
FROM employees
ORDER BY salary DESC
LIMIT 2 OFFSET 2;
Output (Same as ROW_NUMBER() Pagination)
employee_id |
name |
department |
salary |
102 |
Bob |
Sales |
75000 |
103 |
Charlie |
Sales |
75000 |
LIMIT 2 OFFSET 2 skips two rows and fetches the next two, mimicking page 2. However, it lacks ranking and partitioning flexibility, where NTILE() helps segment data into equal-sized groups.
Another useful row function for ranking and segmentation is NTILE(), which divides results into equal-sized groups. This is helpful in percentile-based analysis, such as ranking sales performance across a year.
Example: Dividing Employees into 4 Salary Bands (Quartiles)
SELECT employee_id, name, department, salary,
NTILE(4) OVER (ORDER BY salary DESC) AS salary_quartile
FROM employees;
Output (Dividing Salaries into 4 Groups)
employee_id |
name |
department |
salary |
salary_quartile |
104 |
David |
IT |
90000 |
1 |
105 |
Emma |
IT |
85000 |
1 |
102 |
Bob |
Sales |
75000 |
2 |
103 |
Charlie |
Sales |
75000 |
2 |
101 |
Alice |
Sales |
60000 |
3 |
Efficient pagination improves query performance, but row functions can also be used to extract specific rankings within groups. One common use case is finding the nth highest value per group, such as identifying the second-highest salary in each department.
To retrieve the nth highest value per group, we use ROW_NUMBER() or RANK() within a partitioned query. The following example finds the second-highest salary in each department.
SQL Query to Find 2nd Highest Salary Per Department:
WITH RankedEmployees AS (
SELECT employee_id, name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num
FROM employees
)
SELECT employee_id, name, department, salary
FROM RankedEmployees
WHERE row_num = 2;
Output (Second-Highest Salary Per Department)
employee_id |
name |
department |
salary |
101 |
Alice |
Sales |
60000 |
105 |
Emma |
IT |
85000 |
Here, ROW_NUMBER()assigns a ranking within each gender group.
Finding the nth highest value per group showcases how row functions work within specific categories. To further refine query results, PARTITION BY is used to divide data into logical groups before applying row functions. This ensures rankings, numbering, or segmentation are performed within each partition instead of the entire dataset.
The PARTITION BY clause allows row functions to reset rankings within each group, making it essential for grouped analytics like department-wise rankings or category-based ordering.
SQL Query: Ranking Employees Within Each Department
SELECT employee_id, name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num
FROM employees;
Output (Employee Ranking Per Department):
employee_id |
name |
department |
salary |
row_num |
102 |
Bob |
Sales |
75000 |
1 |
101 |
Alice |
Sales |
60000 |
2 |
103 |
Charlie |
Sales |
50000 |
3 |
104 |
David |
IT |
90000 |
1 |
105 |
Emma |
IT |
85000 |
2 |
Here, PARTITION BY department ensures rankings reset for each department, allowing separate numbering within each category.
Using PARTITION BY allows row functions to operate within specific groups, but sometimes you need a continuous ranking across the entire dataset. In such cases, row functions can be used without PARTITION BY, ensuring a global ranking rather than resetting per group.
When PARTITION BY is omitted, row functions assign numbers or ranks across the entire table rather than within specific groups. This is useful for ranking employees by salary across all departments instead of ranking them within each department separately.
SQL Query: Ranking Employees Without PARTITION BY
SELECT employee_id, name, department, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees;
Output (Global Ranking by Salary):
employee_id |
name |
department |
salary |
row_num |
104 |
David |
IT |
90000 |
1 |
105 |
Emma |
IT |
85000 |
2 |
102 |
Bob |
Sales |
75000 |
3 |
103 |
Charlie |
Sales |
75000 |
4 |
101 |
Alice |
Sales |
60000 |
5 |
Here, ROW_NUMBER() assigns rankings without partitioning, so the numbering continues sequentially across all employees instead of resetting per department.
When using row functions in SQL, the way results are structured depends on whether PARTITION BY is applied or not. Another key aspect to consider is return types, which determine the format and type of data a function produces. Understanding return types in SQL helps ensure accurate query results and better performance.
In SQL, return types define the kind of values a function outputs, such as integers, strings, or dates. Row functions return different results based on how they process data:
Understanding return types in SQL helps in structuring query results effectively. One common use case is retrieving a specific subset of rows from large datasets. This is where Common Table Expressions (CTEs) with ROW_NUMBER() become valuable, allowing you to filter and manage query results efficiently.
Common Table Expressions (CTE) provide a temporary result set that can be referenced within a query. When combined with ROW_NUMBER(), they allow you to filter specific rows, such as selecting the top N records or paginating results.
SQL Query: Retrieve Employees with Row Numbers Between 3 and 4
WITH EmployeeCTE AS (
SELECT employee_id, name, department, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM employees
)
SELECT employee_id, name, department, salary
FROM EmployeeCTE
WHERE row_num BETWEEN 3 AND 4;
Output (Subset of Rows 3 to 4)
employee_id |
name |
department |
salary |
102 |
Bob |
Sales |
75000 |
103 |
Charlie |
Sales |
75000 |
Here, ROW_NUMBER() assigns a ranking, and the CTE filters rows where row_num is between 3 and 4. This technique is useful for pagination, filtering, and ranked queries.
Using CTE with ROW_NUMBER() allows for efficient row filtering and pagination, making queries more manageable. Now, let’s explore real-world use cases where row functions enhance data processing and retrieval in SQL.
Row functions in SQL are widely used in data organization, ranking, and reporting. They help in scenarios like numbering records, ranking employees by performance, or segmenting data for analysis.
One common use case is numbering employees in alphabetical order, which can be useful for organizing HR reports and directories.
To demonstrate, we will create an employees table containing first name, last name, gender, and hire date and use ROW_NUMBER() to assign a unique number to each employee based on alphabetical order.
Sample employees Table
employee_id |
first_name |
last_name |
gender |
hire_date |
1 |
Alice |
Brown |
F |
2018-06-15 |
2 |
David |
Smith |
M |
2016-09-20 |
3 |
Charlie |
Johnson |
M |
2019-02-10 |
4 |
Emma |
Davis |
F |
2017-11-05 |
5 |
Bob |
Adams |
M |
2020-04-25 |
SQL Query: Assigning Row Numbers Alphabetically
SELECT employee_id, first_name, last_name, gender, hire_date,
ROW_NUMBER() OVER (ORDER BY first_name ASC) AS row_num
FROM employees;
Output (Employees Numbered Alphabetically by First Name)
employee_id |
first_name |
last_name |
gender |
hire_date |
row_num |
1 |
Alice |
Brown |
F |
2018-06-15 |
1 |
5 |
Bob |
Adams |
M |
2020-04-25 |
2 |
3 |
Charlie |
Johnson |
M |
2019-02-10 |
3 |
4 |
Emma |
Davis |
F |
2017-11-05 |
4 |
2 |
David |
Smith |
M |
2016-09-20 |
5 |
Here, ROW_NUMBER() assigns a sequential number based on alphabetical order of first names
Organizing employees alphabetically is useful for sorting lists, but another common scenario is ranking employees based on their hire date. This helps in identifying the most recently hired employees, especially when filtering by gender for HR analysis or reporting.
To demonstrate, we will create an employees table and use ROW_NUMBER() to rank employees by their hire date in descending order while also displaying their gender.
Sample employees Table
employee_id |
first_name |
last_name |
gender |
hire_date |
1 |
Alice |
Brown |
F |
2018-06-15 |
2 |
David |
Smith |
M |
2016-09-20 |
3 |
Charlie |
Johnson |
M |
2019-02-10 |
4 |
Emma |
Davis |
F |
2017-11-05 |
5 |
Bob |
Adams |
M |
2020-04-25 |
SQL Query: Assigning Row Numbers by Newest Hire Date
SELECT employee_id, first_name, last_name, gender, hire_date,
ROW_NUMBER() OVER (ORDER BY hire_date DESC) AS row_num
FROM employees;
Output (Employees Ranked by Newest Hire Date):
employee_id |
first_name |
last_name |
gender |
hire_date |
row_num |
5 |
Bob |
Adams |
M |
2020-04-25 |
1 |
3 |
Charlie |
Johnson |
M |
2019-02-10 |
2 |
1 |
Alice |
Brown |
F |
2018-06-15 |
3 |
4 |
Emma |
Davis |
F |
2017-11-05 |
4 |
2 |
David |
Smith |
M |
2016-09-20 |
5 |
Here, ROW_NUMBER() assigns a sequential number based on the most recent hire date, allowing easy identification of the newest employees.
Tracking seniority by hire date is useful, but ordering employees by salary within gender enables pay comparisons. Using JOIN and ROW_NUMBER(), we rank salaries within each gender category.
To demonstrate, we will create two tables:
Sample employees Table
employee_id |
first_name |
last_name |
gender |
hire_date |
1 |
Alice |
Brown |
F |
2018-06-15 |
2 |
David |
Smith |
M |
2016-09-20 |
3 |
Charlie |
Johnson |
M |
2019-02-10 |
4 |
Emma |
Davis |
F |
2017-11-05 |
5 |
Bob |
Adams |
M |
2020-04-25 |
Sample salaries Table
employee_id |
salary |
1 |
70000 |
2 |
85000 |
3 |
75000 |
4 |
72000 |
5 |
90000 |
SQL Query: Assigning Row Numbers by Salary Within Gender
SELECT e.employee_id, e.first_name, e.last_name, e.gender, e.hire_date, s.salary,
ROW_NUMBER() OVER (PARTITION BY e.gender ORDER BY s.salary DESC) AS row_num
FROM employees e
JOIN salaries s ON e.employee_id = s.employee_id;
Output (Employees Ordered by Salary Within Each Gender):
employee_id |
first_name |
last_name |
gender |
hire_date |
salary |
row_num |
4 |
Emma |
Davis |
F |
2017-11-05 |
72000 |
1 |
1 |
Alice |
Brown |
F |
2018-06-15 |
70000 |
2 |
5 |
Bob |
Adams |
M |
2020-04-25 |
90000 |
1 |
2 |
David |
Smith |
M |
2016-09-20 |
85000 |
2 |
3 |
Charlie |
Johnson |
M |
2019-02-10 |
75000 |
3 |
Here, ROW_NUMBER() assigns a ranking within each gender category, ordering employees by salary in descending order.
Ordering employees by salary within gender provides insights into pay distribution, but optimizing row functions is essential for efficient query performance. Proper indexing, partitioning, and filtering techniques can significantly enhance SQL execution speed and accuracy.
Even with best practices, row functions can cause accuracy and performance issues due to missing ORDER BY, inefficient partitioning, or lack of indexing. Avoiding these pitfalls ensures optimized and reliable queries.
Here are common mistakes when using ROW_NUMBER(), RANK(), and DENSE_RANK(), along with solutions to avoid them:
Addressing row function challenges ensures accuracy, but optimizing performance is crucial when handling large datasets in reports, dashboards, or analytics queries. Without proper optimization, ranking operations can slow down performance, especially in real-time applications or high-traffic databases.
Optimizing SQL row functions is crucial when working with large datasets in scenarios like sorting customer transactions, ranking employees, or paginating product listings. Without proper optimization, queries can be slow, leading to performance bottlenecks. Here’s how to improve efficiency with practical examples:
Master row functions in SQL for ranking, segmentation, and query optimization—key skills for efficient database management. upGrad’s programs provide hands-on SQL training, covering structured queries, analytics, and optimization for all skill levels.
Here are some top courses to strengthen your SQL skills:
Looking to advance your SQL and database management career? Get free expert counseling from upGrad to choose the best learning path for you. Visit your nearest upGrad center to elevate your SQL expertise in data analytics and database administration.
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources