MODE() WITHIN GROUP (ORDER BY col) devuelve el valor mas frecuente de una columna — la moda estadistica — en una sola expresion limpia, sin subconsultas ni funciones de ventana. Es un agregado de conjunto ordenado, y el ORDER BY decide que valor gana cuando las frecuencias empatan.
Sintaxis basica
La moda es el valor que aparece con mas frecuencia. En PostgreSQL se escribe como un agregado de conjunto ordenado: tanto WITHIN GROUP como ORDER BY son obligatorios.
SELECT MODE() WITHIN GROUP (ORDER BY status) AS top_status
FROM orders;
SELECT MODE() WITHIN GROUP (ORDER BY country) AS top_country
FROM users;
Conviene tener presente:
- El
ORDER BY aqui no ordena el resultado; nombra la columna sobre la que se calcula la moda y aporta la regla de desempate.
NULL se ignora al contar frecuencias, igual que en los agregados normales.
- Funciona con cualquier tipo ordenable: texto, numeros, fechas, enums.
Moda por grupo
La mayoria de las veces quieres la moda por segmento, no global: el estado mas frecuente de cada usuario, el departamento mas popular por gerente. Agrega GROUP BY.
SELECT user_id,
MODE() WITHIN GROUP (ORDER BY status) AS usual_status
FROM orders
GROUP BY user_id;
SELECT manager_id,
MODE() WITHIN GROUP (ORDER BY dept) AS main_dept
FROM employees
GROUP BY manager_id;
La expresion se lee como una sola columna en el SELECT, asi que otros agregados — COUNT(*), SUM(amount), etc. — conviven a su lado sin joins extra.
Resolucion de empates
El detalle clave: si varios valores comparten la frecuencia maxima, MODE() devuelve el que va primero segun el ORDER BY indicado. Eso hace el resultado determinista — a diferencia de un LIMIT 1 sin orden explicito.
SELECT MODE() WITHIN GROUP (ORDER BY status) AS top_status
FROM orders;
SELECT MODE() WITHIN GROUP (ORDER BY amount DESC) AS top_amount
FROM orders;
Trampa: DESC en el ORDER BY no significa "el valor menos frecuente". La moda se elige igualmente por frecuencia maxima; DESC solo cambia cual de los valores igual de frecuentes gana el empate. Encontrar un valor raro requiere una consulta totalmente distinta con COUNT(*) ordenado ascendente.
Frente a GROUP BY + COUNT + LIMIT 1
La forma clasica de hallar una moda es contar frecuencias y tomar la fila superior:
SELECT status, COUNT(*) AS cnt
FROM orders
GROUP BY status
ORDER BY cnt DESC
LIMIT 1;
Funciona, pero tiene puntos debiles frente a MODE():
- En un empate,
LIMIT 1 toma una fila arbitraria salvo que agregues una segunda clave de orden — el resultado no es determinista.
- Para una moda por grupo hay que recurrir a una funcion de ventana (
ROW_NUMBER() OVER (PARTITION BY ...)) o a una subconsulta correlacionada — bastante mas codigo.
- No puedes poner otros agregados de la misma agrupacion a su lado en un
SELECT simple.
El mismo resultado "moda por usuario" con una ventana se ve asi:
SELECT user_id, status AS usual_status
FROM (
SELECT user_id, status, COUNT(*) AS cnt,
ROW_NUMBER() OVER (PARTITION BY user_id
ORDER BY COUNT(*) DESC, status) AS rn
FROM orders
GROUP BY user_id, status
) t
WHERE rn = 1;
MODE() WITHIN GROUP (ORDER BY status) con GROUP BY user_id hace lo mismo en una linea.
Diferencias entre motores
MODE() como agregado de conjunto ordenado es SQL estandar, soportado por PostgreSQL, Oracle y DB2. Pero varios motores populares no lo tienen:
- MySQL y SQLite: no hay funcion
MODE(). Usa GROUP BY ... ORDER BY COUNT(*) DESC LIMIT 1 o la variante con ventana de arriba.
- ClickHouse: trae funciones aparte —
topK(1)(col) devuelve un arreglo con el valor mas frecuente, y anyHeavy(col) da una moda aproximada sobre flujos grandes.
SELECT topK(1)(status) AS top_status FROM orders;
En resumen: cuando tu base de datos soporta MODE() WITHIN GROUP, es la forma mas corta, legible y determinista de obtener el valor mas frecuente — sobre todo con GROUP BY, donde la alternativa se infla en una subconsulta con funcion de ventana.
MODE() WITHIN GROUP (ORDER BY col)devuelve el valor mas frecuente de una columna — la moda estadistica — en una sola expresion limpia, sin subconsultas ni funciones de ventana. Es un agregado de conjunto ordenado, y elORDER BYdecide que valor gana cuando las frecuencias empatan.Sintaxis basica
La moda es el valor que aparece con mas frecuencia. En PostgreSQL se escribe como un agregado de conjunto ordenado: tanto
WITHIN GROUPcomoORDER BYson obligatorios.-- Most frequent order status across the whole table SELECT MODE() WITHIN GROUP (ORDER BY status) AS top_status FROM orders; -- Most common country among registered users SELECT MODE() WITHIN GROUP (ORDER BY country) AS top_country FROM users;Conviene tener presente:
ORDER BYaqui no ordena el resultado; nombra la columna sobre la que se calcula la moda y aporta la regla de desempate.NULLse ignora al contar frecuencias, igual que en los agregados normales.Moda por grupo
La mayoria de las veces quieres la moda por segmento, no global: el estado mas frecuente de cada usuario, el departamento mas popular por gerente. Agrega
GROUP BY.-- Most frequent status per user SELECT user_id, MODE() WITHIN GROUP (ORDER BY status) AS usual_status FROM orders GROUP BY user_id; -- Dominant department per manager SELECT manager_id, MODE() WITHIN GROUP (ORDER BY dept) AS main_dept FROM employees GROUP BY manager_id;La expresion se lee como una sola columna en el
SELECT, asi que otros agregados —COUNT(*),SUM(amount), etc. — conviven a su lado sin joins extra.Resolucion de empates
El detalle clave: si varios valores comparten la frecuencia maxima,
MODE()devuelve el que va primero segun elORDER BYindicado. Eso hace el resultado determinista — a diferencia de unLIMIT 1sin orden explicito.-- On a tie, the alphabetically smallest status wins SELECT MODE() WITHIN GROUP (ORDER BY status) AS top_status FROM orders; -- Force the tie to resolve toward the largest amount instead SELECT MODE() WITHIN GROUP (ORDER BY amount DESC) AS top_amount FROM orders;Trampa:
DESCen elORDER BYno significa "el valor menos frecuente". La moda se elige igualmente por frecuencia maxima;DESCsolo cambia cual de los valores igual de frecuentes gana el empate. Encontrar un valor raro requiere una consulta totalmente distinta conCOUNT(*)ordenado ascendente.Frente a GROUP BY + COUNT + LIMIT 1
La forma clasica de hallar una moda es contar frecuencias y tomar la fila superior:
-- Old-school: count, sort, take the top row SELECT status, COUNT(*) AS cnt FROM orders GROUP BY status ORDER BY cnt DESC LIMIT 1;Funciona, pero tiene puntos debiles frente a
MODE():LIMIT 1toma una fila arbitraria salvo que agregues una segunda clave de orden — el resultado no es determinista.ROW_NUMBER() OVER (PARTITION BY ...)) o a una subconsulta correlacionada — bastante mas codigo.SELECTsimple.El mismo resultado "moda por usuario" con una ventana se ve asi:
-- Per-group mode the hard way SELECT user_id, status AS usual_status FROM ( SELECT user_id, status, COUNT(*) AS cnt, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY COUNT(*) DESC, status) AS rn FROM orders GROUP BY user_id, status ) t WHERE rn = 1;MODE() WITHIN GROUP (ORDER BY status)conGROUP BY user_idhace lo mismo en una linea.Diferencias entre motores
MODE()como agregado de conjunto ordenado es SQL estandar, soportado por PostgreSQL, Oracle y DB2. Pero varios motores populares no lo tienen:MODE(). UsaGROUP BY ... ORDER BY COUNT(*) DESC LIMIT 1o la variante con ventana de arriba.topK(1)(col)devuelve un arreglo con el valor mas frecuente, yanyHeavy(col)da una moda aproximada sobre flujos grandes.-- ClickHouse: most frequent value as a 1-element array SELECT topK(1)(status) AS top_status FROM orders;En resumen: cuando tu base de datos soporta
MODE() WITHIN GROUP, es la forma mas corta, legible y determinista de obtener el valor mas frecuente — sobre todo conGROUP BY, donde la alternativa se infla en una subconsulta con funcion de ventana.