When analyzing data, averages can be misleading. A few outliers can skew the mean dramatically. That's why professionals rely on median and percentiles for more robust insights.
But SQL doesn't have a built-in MEDIAN() function in most databases. Let's explore how to calculate these statistics anyway.

Why Median Matters
Consider employee salaries:
- Mean salary: $100,000
- But if the CEO makes $1,000,000 and everyone else makes $50,000, the mean is misleading!
- Median salary: $50,000 (the "middle" value) tells the real story.
Method 1: Using PERCENT_RANK for Percentiles
The PERCENT_RANK() function assigns a percentile rank (0 to 1) to each row:
A percentile of 50 means half the data is below that value.
Method 2: Finding the Median with Window Functions
The median is the value at the 50th percentile. Here's how to find it:
How This Works
ROW_NUMBER()assigns position 1 to NCOUNT(*) OVER ()gets the total count- For odd counts:
(N+1)/2gives the middle position - For even counts: Average of positions
N/2andN/2+1
Method 3: NTILE for Quartiles
NTILE(4) divides data into 4 equal groups (quartiles):
You can use NTILE(10) for deciles or NTILE(100) for fine-grained percentiles.
Method 4: Percentile Boundaries
Find the value at a specific percentile (e.g., 90th percentile):
Calculating Multiple Percentiles at Once
Need P25, P50 (median), and P75? Use conditional aggregation:
Group-Level Percentiles
Calculate median salary per department:
SELECT
department,
AVG(salary) as median_salary
FROM (
SELECT
department,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary
) as rn,
COUNT(*) OVER (PARTITION BY department) as dept_count
FROM employees
)
WHERE rn IN ((dept_count + 1) / 2, (dept_count + 2) / 2)
GROUP BY department;
Comparison: Mean vs Median
Notice how the outlier ($500,000) dramatically affects the mean but not the median!
Quick Reference
| Statistic | SQL Approach |
|---|---|
| Percentile rank | PERCENT_RANK() OVER (ORDER BY col) |
| Median | ROW_NUMBER() + middle position formula |
| Quartiles (4 groups) | NTILE(4) OVER (ORDER BY col) |
| Deciles (10 groups) | NTILE(10) OVER (ORDER BY col) |
| Specific percentile | NTILE(100) + filter |
Best Practices
-
Use median for skewed data: Income, prices, and response times often have outliers.
-
Report both mean and median: If they differ significantly, your data is skewed.
-
Consider NTILE limitations: With small datasets, NTILE groups may be uneven.
-
Index the ORDER BY column: Percentile calculations sort data, so indexes help.
Tool Workflow
Use tools when percentile SQL is correct mathematically but still hard to audit
Median and percentile queries often combine ranking, tiling, and nested calculations. Use the tools to inspect the window logic and confirm that the statistic matches the business question.
Conclusion
While SQL lacks a native MEDIAN() in most databases, window functions provide powerful alternatives:
- PERCENT_RANK() for percentile ranks
- NTILE() for dividing into groups
- ROW_NUMBER() with arithmetic for exact median
These techniques give you robust statistical insights that go beyond simple averages.
Related Articles
- Understanding Window Functions: A Practical Guide for the foundation behind ranking and distribution-style analytics.
- Descriptive Statistics in SQL: Mean, Median, Mode, and More for the broader summary-statistics toolkit around percentiles.
- SQL Histograms and Frequency Distributions for another way to understand distributions beyond a single average.