Learnitweb

PARTITION BY Clause

In Oracle SQL, the PARTITION BY clause is used with analytic (window) functions to divide the result set into groups or partitions, over which the analytic function is applied independently.

This is similar to how GROUP BY works in aggregate functions, but with one major difference:

GROUP BY collapses rows into one per group, whereas PARTITION BY retains all rows and just scopes the analytic function to partitions.

1. Syntax

<ANALYTIC_FUNCTION>() OVER (
  PARTITION BY column1, column2, ...
  ORDER BY column3
)

Components:

  • ANALYTIC_FUNCTION() – Any analytic function like RANK(), DENSE_RANK(), ROW_NUMBER(), SUM(), etc.
  • PARTITION BY – Divides the result set into subsets.
  • ORDER BY – Specifies how to order rows within each partition.

2. Why Use PARTITION BY?

  • To restart calculations (like rankings, sums) for each group.
  • To perform cumulative totals, running averages, or windowed calculations on groups of data without aggregating or collapsing rows.
  • To enhance performance and accuracy of reports and analytics.

3. Example Table: employees

CREATE TABLE employees (
  employee_id   NUMBER,
  name          VARCHAR2(50),
  department_id NUMBER,
  salary        NUMBER
);

INSERT INTO employees VALUES (1, 'Alice', 10, 5000);
INSERT INTO employees VALUES (2, 'Bob', 10, 7000);
INSERT INTO employees VALUES (3, 'Charlie', 20, 6000);
INSERT INTO employees VALUES (4, 'David', 20, 6000);
INSERT INTO employees VALUES (5, 'Eve', 10, 7000);
COMMIT;

4. Example: RANK() with and without PARTITION BY

Without PARTITION BY – One global ranking:

SELECT name, department_id, salary,
       RANK() OVER (ORDER BY salary DESC) AS rank
FROM employees;

Output:

NAMEDEPT_IDSALARYRANK
Bob1070001
Eve1070001
Charlie2060003
David2060003
Alice1050005

With PARTITION BY – Ranking per department:

SELECT name, department_id, salary,
       RANK() OVER (
         PARTITION BY department_id
         ORDER BY salary DESC
       ) AS dept_rank
FROM employees;

Output:

NAMEDEPT_IDSALARYDEPT_RANK
Bob1070001
Eve1070001
Alice1050003
Charlie2060001
David2060001

Explanation:

  • RANK() restarts for each department_id.
  • Within each department, salaries are ranked independently.

5. Example: Cumulative Salary per Department

SELECT name, department_id, salary,
       SUM(salary) OVER (
         PARTITION BY department_id
         ORDER BY salary
       ) AS running_salary
FROM employees;

Output:

NAMEDEPT_IDSALARYRUNNING_SALARY
Alice1050005000
Bob10700012000
Eve10700019000
Charlie2060006000
David20600012000

Explanation:

  • Running total resets with each department_id.

6. Example: ROW_NUMBER() in Partitions

Get the first employee per department by salary:

SELECT *
FROM (
  SELECT name, department_id, salary,
         ROW_NUMBER() OVER (
           PARTITION BY department_id
           ORDER BY salary DESC
         ) AS rn
  FROM employees
)
WHERE rn = 1;

Output:

NAMEDEPT_IDSALARYRN
Bob1070001
Charlie2060001

7. PARTITION BY with Aggregate vs Analytic

Using GROUP BY:

SELECT department_id, SUM(salary)
FROM employees
GROUP BY department_id;

This collapses rows to department level.

Using PARTITION BY:

SELECT name, department_id, salary,
       SUM(salary) OVER (PARTITION BY department_id) AS dept_total
FROM employees;

This retains all rows, adds department total per row.

8. Real-World Use Case: Top 2 Salaries Per Department

SELECT *
FROM (
  SELECT name, department_id, salary,
         DENSE_RANK() OVER (
           PARTITION BY department_id
           ORDER BY salary DESC
         ) AS rnk
  FROM employees
)
WHERE rnk <= 2;

9. Notes and Best Practices

  • Use PARTITION BY only with analytic/window functions (RANK, SUM, AVG, ROW_NUMBER, etc.).
  • Avoid confusion with GROUP BY. They serve different purposes.
  • Ensure ORDER BY is also used inside OVER() when ordering matters (e.g. RANK()).

10. Summary Table

FeatureGROUP BYPARTITION BY
PurposeGroup rows into single outputDivide rows into groups without collapsing
Used WithAggregate functionsAnalytic (window) functions
Rows ReturnedOne per groupAll rows
Ranking, Running Total❌ Not possible✅ Possible
Ordering ControlIndirectDirect with ORDER BY inside OVER()

11. Conclusion

The PARTITION BY clause is a powerful tool in Oracle SQL for grouped analytics without data loss. Use it when you need:

  • Ranking per category (e.g. department, region)
  • Running totals, moving averages
  • Filtering top-N per group
  • Grouped calculations while keeping all original rows

It is essential for data reporting, analytics, and dashboard queries in Oracle.