SQL estándar no tiene una función MEDIAN, y cada motor la resuelve distinto. En PostgreSQL usa PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY columna); en SQL Server, la misma función pero con OVER () obligatorio; en Oracle, MEDIAN(columna). MySQL no tiene ninguna de las dos, así que se calcula numerando las filas con ROW_NUMBER() y promediando la fila o las dos filas centrales.
Sintaxis por motor
| Motor | Mediana de toda la tabla | Por grupo |
|---|---|---|
| PostgreSQL | PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x) | Igual, con GROUP BY |
| SQL Server | PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x) OVER () | OVER (PARTITION BY g) y DISTINCT |
| Oracle | MEDIAN(x) | Igual, con GROUP BY |
| MySQL 8 | Consulta con ROW_NUMBER() (abajo) | Igual, con PARTITION BY |
| SQLite | median(x) solo si está la extensión percentile; si no, ROW_NUMBER() | Igual |
PERCENTILE_CONT interpola: con una cantidad par devuelve el promedio de los dos centrales, como la mediana de los libros. PERCENTILE_DISC(0.5) devuelve siempre un valor que existe en los datos (el menor de los dos centrales).
Paso a paso
- Identifica tu motor y su versión: las funciones de ventana de MySQL requieren la 8.0 o posterior.
- Si tu motor tiene
PERCENTILE_CONToMEDIAN, úsalo con0.5. - Si no, numera las filas ordenadas con
ROW_NUMBER()y cuenta las del grupo conCOUNT(*) OVER. - Quédate con la fila central (cantidad impar) o las dos centrales (par) y promedia.
- Compara la mediana con el promedio para ver si hay valores extremos.
Tabla de ejemplo:
CREATE TABLE sueldos (
empleado VARCHAR(20),
area VARCHAR(20),
sueldo DECIMAL(10, 2)
);
INSERT INTO sueldos VALUES
('E1', 'Ventas', 14500), ('E2', 'Ventas', 16200), ('E3', 'Ventas', 15800),
('E4', 'Ventas', 61000), ('E5', 'Sistemas', 28000), ('E6', 'Sistemas', 31500),
('E7', 'Sistemas', 26000);
Ejemplos resueltos
Ejemplo 1: PostgreSQL y SQL Server
En PostgreSQL, PERCENTILE_CONT es un agregado y se combina con GROUP BY:
SELECT area,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sueldo) AS mediana,
AVG(sueldo) AS promedio
FROM sueldos
GROUP BY area;
En SQL Server es una función analítica: devuelve un valor en cada fila, así que se usa PARTITION BY y DISTINCT para quedarse con una fila por área:
SELECT DISTINCT area,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY sueldo)
OVER (PARTITION BY area) AS mediana
FROM sueldos;
| area | mediana | promedio |
|---|---|---|
| Sistemas | 28000 | 28500 |
| Ventas | 16000 | 26875 |
En Ventas, el sueldo de 61,000 empuja el promedio a 26,875, por encima de lo que gana 3 de cada 4 personas del área. La mediana, 16,000, es el promedio de los dos centrales (15,800 y 16,200).
Ejemplo 2: MySQL 8 y cualquier motor con funciones de ventana
WITH ordenados AS (
SELECT area, sueldo,
ROW_NUMBER() OVER (PARTITION BY area ORDER BY sueldo) AS fila,
COUNT(*) OVER (PARTITION BY area) AS n
FROM sueldos
)
SELECT area, AVG(sueldo) AS mediana
FROM ordenados
WHERE fila BETWEEN n / 2.0 AND n / 2.0 + 1
GROUP BY area;
| area | mediana |
|---|---|
| Sistemas | 28000.0 |
| Ventas | 16000.0 |
Ventas tiene 4 filas: la condición queda fila BETWEEN 2 AND 3 y se promedian las filas 2 y 3. Sistemas tiene 3: queda BETWEEN 1.5 AND 2.5 y solo entra la fila 2. Usar 2.0 en lugar de 2 es deliberado: evita que el resultado dependa de la división entera, que en MySQL no existe con / y en PostgreSQL, SQL Server y SQLite sí. Esta consulta, ejecutada en SQLite, funciona sin cambios en MySQL 8, PostgreSQL y SQL Server.
Ejemplo 3: mediana de toda la tabla en SQLite
La consola sqlite3 reciente incluye la extensión percentile, que agrega median():
SELECT median(sueldo) AS mediana, AVG(sueldo) AS promedio FROM sueldos;
| mediana | promedio |
|---|---|
| 26000.0 | 27571.428571428573 |
Con 7 sueldos, la mediana es el cuarto valor ordenado. Si tu programa usa una biblioteca de SQLite compilada sin esa extensión, median da error no such function; usa entonces la consulta del ejemplo 2 sin PARTITION BY.
Errores comunes
The function 'PERCENTILE_CONT' must have an OVER clauseen SQL Server. Allí no es un agregado: agregaOVER ()uOVER (PARTITION BY ...).- Olvidar el
DISTINCTen SQL Server. Sin él obtienes la mediana repetida en cada fila del grupo. ORDER BYsinROW_NUMBERcorrecto. Si numeras sinPARTITION BYpero cuentas conPARTITION BY(o al revés), las filas centrales salen mal.- NULL en los datos.
PERCENTILE_CONTyMEDIANlos ignoran, peroROW_NUMBER()yCOUNT(*)los numeran. AgregaWHERE sueldo IS NOT NULLdentro delWITH. - Elegir
PERCENTILE_DISCsin querer. Con cantidad par devuelve 15,800 en Ventas, no 16,000.
Comprueba resultados con la calculadora de mediana. El concepto, y cuándo conviene más que el promedio, está en mediana.
Fuentes
- PostgreSQL, funciones de agregado de conjunto ordenado. percentile_cont y percentile_disc con WITHIN GROUP. Consultado el 11 de noviembre de 2026.
- Microsoft Learn, PERCENTILE_CONT (Transact-SQL). Función analítica con cláusula OVER obligatoria. Consultado el 11 de noviembre de 2026.
- SQLite, extensión percentile. median() y percentile_cont(). Consultado el 11 de noviembre de 2026.