Example 1
Find the median API response time from five samples
The five values sorted are 88, 95, 120, 145, 310. The middle value (position 3 of 5) is 120, making the median 120. PostgreSQL and MariaDB call PERCENTILE_CONT(0.5) as a plain aggregate. SQL Server's version is a window function that outputs a value for every input row — DISTINCT collapses those five identical 120 values into one row. The MySQL and SQLite workaround uses ROW_NUMBER to label rows 1–5 and COUNT(*) OVER () to get the total, then selects the middle row(s) — FLOOR((5+1)/2) and CEIL((5+1)/2) both equal 3 — and averages them. For an even row count, both floor and ceil pick different rows and AVG interpolates between them, matching PERCENTILE_CONT behaviour.
CREATE TABLE response_times (endpoint VARCHAR(50), ms INT);
INSERT INTO
response_times
VALUES
('GET /api/users', 120),
('GET /api/users', 95),
('GET /api/users', 310),
('GET /api/users', 88),
('GET /api/users', 145);SELECT
AVG(ms) AS median_ms
FROM
(
SELECT
ms,
ROW_NUMBER() OVER (
ORDER BY
ms
) AS rn,
COUNT(*) OVER () AS cnt
FROM
response_times
) t
WHERE
rn IN (FLOOR((cnt + 1) / 2.0), CEIL((cnt + 1) / 2.0));| median_ms |
|---|
| 120 |
CREATE TABLE response_times (endpoint VARCHAR(50), ms INT);
INSERT INTO
response_times
VALUES
('GET /api/users', 120),
('GET /api/users', 95),
('GET /api/users', 310),
('GET /api/users', 88),
('GET /api/users', 145);SELECT
PERCENTILE_CONT(0.5) WITHIN GROUP (
ORDER BY
ms
) AS median_ms
FROM
response_times;| median_ms |
|---|
| 120 |
CREATE TABLE response_times (endpoint VARCHAR(50), ms INT);
INSERT INTO
response_times
VALUES
('GET /api/users', 120),
('GET /api/users', 95),
('GET /api/users', 310),
('GET /api/users', 88),
('GET /api/users', 145);SELECT DISTINCT
PERCENTILE_CONT(0.5) WITHIN GROUP (
ORDER BY
ms
) OVER () AS median_ms
FROM
response_times;| median_ms |
|---|
| 120 |
PostgreSQL and MariaDB use a direct ordered-set aggregate. SQL Server requires OVER() and DISTINCT. MySQL and SQLite use a ROW_NUMBER workaround.