- Aprender
- Informática
- Programación
- Fundamentos de SQL
- Agregación y agrupación en SQL
Agregación y agrupación en SQL
PrincipianteUnidad 4 de 6 del curso Curso de Fundamentos de SQL
Lo que aprenderás
- Utiliza COUNT, SUM, AVG, MIN y MAX para convertir muchas filas en valores de resumen, elegir el tipo de recuento adecuado y predecir cómo cambian un resultado los valores ausentes.
- Obtén totales, promedios y valores mínimos y máximosUtiliza SUM, AVG, MIN y MAX sobre una tabla completa o sobre las filas que conserva una cláusula WHERE, y combina varias de estas funciones en una consulta.
- Cuenta filas, valores y valores distintosElige entre COUNT(*), COUNT(column) y COUNT(DISTINCT column), y comprende cómo trata cada uno los valores repetidos y ausentes.
- Predice cómo afectan los valores NULL a las funciones de agregaciónComprende que las funciones de agregación omiten los valores NULL, predice los resultados para conjuntos de entrada vacíos y sustituye NULL por un valor predeterminado cuando la pregunta lo requiera.
- Obtén totales, promedios y valores mínimos y máximos
- Utiliza GROUP BY para obtener una fila de resumen por categoría, por combinación de valores o por valor calculado, y aplica la regla que determina qué puede mostrar una consulta agrupada.
- Resume cada categoría con GROUP BYDivide una tabla en grupos que comparten un valor, calcula funciones de agregación por grupo y ordena y limita el resultado agrupado.
- Aplica la regla que determina qué puede mostrar una consulta agrupadaComprende qué columnas pueden aparecer en la lista SELECT de una consulta agrupada, corrige el error que aparece cuando se incumple la regla y reconoce las diferencias entre bases de datos.
- Agrupa por varias columnas y por valores calculadosAgrupa filas por combinaciones de columnas y por expresiones, como el mes de una fecha o una categoría definida con CASE, e interpreta el resultado más detallado.
- Resume cada categoría con GROUP BY
- Conserva solo los grupos cuyos totales, recuentos o promedios cumplen una condición, y decide si una condición corresponde a WHERE o a HAVING.
- Conserva los grupos que cumplen una condiciónEscribe condiciones HAVING sobre valores de agregación, incluidos los que no se muestran, para filtrar un resultado agrupado.
- Elige entre WHERE y HAVINGUtiliza el orden lógico de una consulta para decidir si una condición filtra filas o grupos, y predice cómo cambia el resultado esa elección.
- Conserva los grupos que cumplen una condición
- Evita la división entera, comprende qué tipo de número devuelve cada función de agregación y redondea promedios, totales y porcentajes en el momento adecuado.
- Evita la división entera en promedios y porcentajesReconoce cuándo la división de resultados de agregación pierde los decimales, corrígela con un operando decimal y comprende las diferencias entre los tipos de resultado de las bases de datos.
- Redondea los resultados de agregaciónRedondea promedios, totales y porcentajes con ROUND, hazlo en el momento adecuado y gestiona las diferencias entre SQLite y PostgreSQL.
- Evita la división entera en promedios y porcentajes
- Combina CASE con funciones de agregación para obtener recuentos, totales y porcentajes condicionales, y convierte una pregunta en una consulta agrupada cuyas cifras puedas comprobar.
- Cuenta y suma según una condición con CASEColoca una expresión CASE dentro de una función de agregación para calcular varios recuentos, totales y porcentajes condicionales en una consulta agrupada.
- Construye y comprueba una consulta de resumen a partir de una preguntaConvierte una pregunta de negocio en una consulta agrupada paso a paso, evita confundir los niveles de detalle y comprueba que las cifras sean correctas.
- Cuenta y suma según una condición con CASE
Guía de estudio de Agregación y agrupación en SQL
1Resume datos con funciones de agregación
Una tabla registra hechos individuales; un informe suele necesitar unas pocas cifras que los describan en conjunto. Las funciones de agregación convierten filas en recuentos, totales, promedios y valores extremos. Elegir la función es solo parte del trabajo: también debes decidir qué filas entran en el cálculo y qué significan los valores ausentes. Utilizaremos una pequeña tabla de pedidos para comprobar cada respuesta a mano antes de confiar en la consulta.
1.1 Obtén totales, promedios y valores mínimos y máximos
Una función de agregación combina valores de muchas filas en un resultado. Oracle también la llama función de grupo. Sin GROUP BY, una consulta de agregación trata todas las filas que pasan WHERE como un grupo y devuelve una fila de resumen.
Empieza con datos que puedas comprobar
Cada fila de orders es un pedido. Las columnas numéricas siguientes contienen números enteros; order_id es la clave primaria. Las fechas utilizan texto ISO en SQLite y el tipo DATE en PostgreSQL.
| order_id | customer | region | amount | quantity | discount | order_date |
|---|---|---|---|---|---|---|
| 1 | Ana | East | 120 | 2 | 10 | 2026-01-05 |
| 2 | Ben | West | 80 | 1 | NULL | 2026-01-17 |
| 3 | Ana | East | 45 | 3 | 5 | 2026-02-02 |
| 4 | Chen | North | 200 | 4 | NULL | 2026-02-14 |
| 5 | Ben | West | 60 | 1 | 0 | 2026-02-20 |
| 6 | Dara | East | 95 | 2 | NULL | 2026-03-03 |
| 7 | Chen | North | 150 | 5 | 15 | 2026-03-09 |
| 8 | Eli | NULL | 30 | 1 | NULL | 2026-03-21 |
Elige la medida
SUM(amount) suma los importes. AVG(amount) da su media aritmética. MIN(amount) encuentra el importe mínimo y MAX(amount) encuentra el máximo. Puedes solicitar las cuatro en una consulta:
SELECT SUM(amount) AS total, AVG(amount) AS avg_amount, MIN(amount) AS smallest, MAX(amount) AS largest FROM orders;
El resultado es una fila: total 780, promedio 97,5, mínimo 30 y máximo 200. Suma los ocho importes para obtener 780 y después divide entre ocho para obtener 97,5. Cada función utiliza las mismas ocho filas de entrada. Los alias claros después de AS hacen que los encabezados de salida sean útiles; un encabezado generado como sum dice poco sobre lo que se ha sumado.
Filtra antes de calcular
Para resumir los pedidos de East, escribe SELECT COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE region = 'East';. El filtro conserva los importes 120, 45 y 95. La consulta devuelve tres pedidos y un total de 260. WHERE elige las filas de entrada antes de ejecutar cualquier función de agregación.
Una función de agregación también puede recibir una expresión calculada. En una tabla con quantity y unit_price, SUM(quantity * unit_price) primero calcula los ingresos de cada fila y después los suma. Dos filas, dos artículos a 5 y tres artículos a 10, aportan 10 y 30, para un total de 40. En cambio, SUM(quantity) * SUM(unit_price) multiplica 5 por 15 y da 75. Mantener el cálculo dentro de SUM conserva la correspondencia entre cada cantidad y su precio.
Interpreta correctamente los valores extremos
MIN(order_date) es 2026-01-05 y MAX(order_date) es 2026-03-21. Los valores de fecha y el texto de fecha ISO se ordenan cronológicamente. Un texto como «03/21/2026» sigue el orden de los caracteres, que no coincide de forma fiable con el orden de las fechas. Los valores extremos de texto también siguen la intercalación de la base de datos, sus reglas para comparar texto. Aquí los clientes extremos son «Ana» y «Eli»; mezclar mayúsculas y minúsculas puede cambiar la ordenación del texto.
MAX(amount) devuelve un importe, no el pedido completo que lo contiene. Para mostrar un cliente con un pedido de importe máximo, utiliza SELECT customer, amount FROM orders ORDER BY amount DESC LIMIT 1;. PostgreSQL rechaza una columna customer sin agregar junto a MAX(amount) sin una agrupación adecuada. SQLite tiene una regla especial para un único MIN o MAX que puede devolver una columna contigua de la fila extrema, pero los extremos empatados siguen necesitando una regla de desempate.
Puntos clave
- Una función de agregación devuelve un valor para un conjunto de filas.
WHEREselecciona las filas que utiliza la función de agregación.- Calcula la aportación de cada fila dentro de
SUMcuando los valores deban mantenerse emparejados. MINyMAXsiguen el orden numérico, de fechas o de texto.- Un valor extremo no identifica una fila completa.
1.2 Cuenta filas, valores y valores distintos
«¿Cuántos?» puede preguntar por filas, valores registrados o valores diferentes. Son recuentos distintos, aunque en una tabla pequeña puedan dar por casualidad el mismo número.
Tres formas de COUNT
| Expresión | Qué cuenta |
|---|---|
COUNT(*) | Todas las filas de entrada |
COUNT(region) | Filas con una región que no es NULL |
COUNT(DISTINCT region) | Valores diferentes de región que no son NULL |
En la tabla de pedidos, las regiones son East, West, East, North, West, East, North y NULL. SELECT COUNT(*) AS order_rows, COUNT(region) AS with_region, COUNT(DISTINCT region) AS regions FROM orders; devuelve 8, 7 y 3. Los nombres de región repetidos se cuentan por separado en COUNT(region), pero cada nombre contribuye solo una vez al recuento de valores distintos.
Para «¿Cuántos clientes diferentes hicieron pedidos?», utiliza COUNT(DISTINCT customer). Ana, Ben y Chen aparecen dos veces cada uno, mientras que Dara y Eli aparecen una vez, por lo que la respuesta es cinco clientes. COUNT(customer) devuelve ocho porque todos los pedidos indican un cliente. Mide filas de pedido que indican un cliente, no personas.
Un cero registrado también cuenta
Los descuentos son 10, NULL, 5, NULL, 0, NULL, 15 y NULL. COUNT(discount) devuelve cuatro. El cero registra un valor conocido y cuenta igual que 10, 5 y 15. Una cadena vacía también es un valor en SQLite y PostgreSQL; Oracle trata una cadena vacía como NULL.
Resta el recuento de valores que no son NULL del recuento de filas para medir los registros sin ese dato: SELECT COUNT(*) - COUNT(region) AS missing_region FROM orders; devuelve uno. Esto funciona porque ambos recuentos utilizan exactamente las mismas filas de entrada.
Listas de valores distintos y recuentos de valores distintos
SELECT DISTINCT region FROM orders; enumera East, West, North y una fila NULL. Su función es devolver valores diferentes, y NULL permanece en esa lista. COUNT(DISTINCT region) devuelve tres porque el recuento ignora NULL. No deduzcas un recuento de valores distintos contando una lista sin haber decidido si debe incluir su fila NULL.
DISTINCT también puede aparecer dentro de SUM o AVG. Las cantidades son 2, 1, 3, 4, 1, 2, 5 y 1. Su suma normal es 19. SUM(DISTINCT quantity) conserva solo 1, 2, 3, 4 y 5, lo que da 15. Las cantidades repetidas suelen describir ventas adicionales reales. Eliminarlas cambia la medida; no corrige registros duplicados.
Cuenta combinaciones en dos pasos
Para obtener pares diferentes de región y cliente, crea primero una lista sin duplicados:
SELECT COUNT(*) FROM (SELECT DISTINCT region, customer FROM orders) AS pairs;
La consulta interna devuelve cinco pares: East/Ana, East/Dara, North/Chen, West/Ben y NULL/Eli. El COUNT(*) externo cuenta esas cinco filas, incluida NULL/Eli. Esta forma funciona en SQLite y PostgreSQL. MySQL también acepta COUNT(DISTINCT region, customer), pero esa forma excluye las combinaciones que contienen NULL, por lo que puede responder otra pregunta. En SQLite y PostgreSQL, la forma separada por comas no es válida.
Por último, un recuento nunca devuelve NULL. SELECT COUNT(*) FROM orders WHERE region = 'South'; devuelve una fila de resumen que contiene cero, porque no hay pedidos que coincidan.
Puntos clave
- Elige entre filas, valores registrados y valores registrados diferentes.
- El cero es un valor registrado, por lo que
COUNT(column)lo incluye. - Una lista de valores distintos puede incluir NULL;
COUNT(DISTINCT column)lo omite. SUM(DISTINCT x)elimina valores repetidos, incluidas las repeticiones legítimas.- Cuenta combinaciones distintas contando las filas de un resultado interno sin duplicados.
COUNTdevuelve cero para un conjunto de entrada vacío.
1.3 Predice cómo afectan los valores NULL a las funciones de agregación
NULL significa que un valor está ausente o es desconocido. Cambia los valores que recibe una función de agregación, por lo que un total o promedio puede ser válido en SQL y, aun así, medir algo diferente de lo que pretendías.
Determina el denominador
Supón que scores contiene Ana 80, Ben NULL, Chen 70 y Dara 90. SUM(score) es 240, COUNT(score) es tres y COUNT(*) es cuatro. AVG(score) es 80: las tres calificaciones registradas suman 240 y se dividen entre tres.
Las cinco funciones de agregación estándar ignoran los argumentos NULL. COUNT(*) cuenta todas las filas porque no evalúa un argumento de columna. MIN(score) es 70 y MAX(score) es 90; NULL no se convierte en la calificación mínima ni en la máxima. Esto difiere de la ordenación, en la que los valores NULL ocupan un extremo del resultado: al principio en una ordenación ascendente de SQLite y al final en una ordenación ascendente de PostgreSQL.
Un promedio calculado manualmente necesita el recuento de valores que no son NULL: 1.0 * SUM(score) / NULLIF(COUNT(score), 0). El operando decimal conserva los resultados fraccionarios, y NULLIF convierte en NULL un divisor cero. Dividir entre COUNT(*) daría 60 y, en la práctica, trataría la calificación ausente como cero.
Decide qué significa un valor predeterminado
COALESCE devuelve el primer argumento que no es NULL. Si Ben aún no ha sido calificado, deja su calificación ausente y calcula el promedio de los resultados conocidos. Si la ausencia a un examen se registra como NULL pero debe contar como cero, AVG(COALESCE(score, 0)) calcula el promedio de 80, 0, 70 y 90, que da 60. El significado de los datos determina si esa sustitución está justificada.
Compara colocar COALESCE dentro y fuera de una función. AVG(COALESCE(score, 0)) cambia los valores que entran en el promedio. COALESCE(AVG(score), 0) cambia solo un resultado final NULL; sigue dando 80 para estas calificaciones. NVL(x, 0) de Oracle es otra forma con dos argumentos para sustituir NULL.
Distingue entre ausencia de filas y ausencia de valores registrados
Con WHERE region = 'South', no queda ningún pedido. Una consulta de agregación sin GROUP BY sigue devolviendo una fila: COUNT(*) es cero, mientras que SUM(amount), AVG(amount), MIN(amount) y MAX(amount) son NULL. Para mostrar un total vacío como cero, utiliza COALESCE(SUM(amount), 0). SQLite también ofrece TOTAL(amount), que devuelve 0,0 para un conjunto de entrada vacío.
Ahora conserva los cuatro pedidos cuyo descuento es NULL. Hay filas, pero no hay valores de descuento registrados: COUNT(*) es cuatro, COUNT(discount) es cero y SUM(discount) es NULL. Cero valores registrados y cuatro valores ausentes son observaciones diferentes.
Comprueba las expresiones antes de que entren en SUM
Las operaciones aritméticas con NULL producen NULL. En SUM(amount - discount), los cuatro pedidos sin un descuento registrado no aportan ningún valor. Solo contribuyen las filas con descuento conocido: 110, 40, 60 y 135, que suman 345.
Si un descuento ausente significa que no hay descuento, escribe SUM(amount - COALESCE(discount, 0)). Así contribuyen todos los pedidos; el importe total de 780 menos los descuentos registrados de 30 da 750. Envolver toda la suma en COALESCE no recuperaría los pedidos omitidos, porque 345 ya es un valor que no es NULL.
Para localizar valores ausentes, utiliza IS NULL o IS NOT NULL. WHERE discount IS NULL encuentra cuatro pedidos. discount = NULL nunca es verdadero y, por tanto, no puede seleccionarlos.
Puntos clave
AVG(x)divide entre el número de valores que no son NULL.- Un
COALESCEinterno cambia los valores de entrada; uno externo cambia un resultado NULL. - Un conjunto de entrada vacío da cero para
COUNTy NULL para las otras cuatro funciones de agregación. - NULL dentro de una expresión aritmética puede eliminar la aportación de una fila.
2Agrupa filas y resume cada grupo
Un total de toda la tabla responde una pregunta, pero muchos informes piden un resultado por cliente, región o mes. La agrupación establece ese nivel de detalle antes de ejecutar las funciones de agregación. Seguirás cómo las filas se convierten en grupos, elegirás columnas que puedan describir un grupo completo y verás cómo cambia el informe al añadir una columna de agrupación. Después, la ordenación decide cómo presentar los resultados; la agrupación por sí sola no les da un orden.
2.1 Resume cada categoría con GROUP BY
GROUP BY reúne filas que comparten un valor de agrupación. Cada función de agregación se ejecuta por separado dentro de cada grupo, y la salida contiene una fila por cada grupo que existe después del filtrado.
Decide qué significa una fila del resultado
«Ventas totales por región» pide una fila de salida por región. Empieza escribiendo esa frase y después utiliza region como columna de agrupación:
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region;
Los tres importes de East, 120, 45 y 95, forman un grupo. Su recuento es tres y su total es 260. North tiene dos pedidos que suman 350; West tiene dos que suman 140. El pedido de Eli forma un grupo de región NULL con un pedido que suma 30. Hay cuatro filas de resultado, no ocho.
Lee la consulta como una secuencia: FROM aporta pedidos, cualquier WHERE elimina filas, GROUP BY reúne las filas restantes por región y las funciones de agregación resumen cada conjunto. SELECT muestra su etiqueta y sus medidas. La agrupación no descarta los pedidos menores dentro de un grupo; todos contribuyen salvo que un filtro de filas los haya eliminado.
Mantén visibles las categorías ausentes
Las filas con NULL en la columna de agrupación pertenecen a un grupo NULL. Esto es útil: un informe puede mostrar cuánta actividad no tiene una región registrada. No trata cada región ausente como una categoría diferente.
Para mostrar una etiqueta legible, selecciona COALESCE(region, 'No region') AS region_label y conserva GROUP BY region. La etiqueta cambia el valor mostrado. Para excluir esas filas de los cálculos, añade WHERE region IS NOT NULL antes de GROUP BY. Los totales resultantes suman 750, porque se ha excluido el importe de 30 de Eli.
Una consulta agrupada sobre un conjunto de entrada sin filas no devuelve grupos. Por ejemplo, filtrar la tabla para South y después agrupar por región no devuelve filas de resultado. Eso difiere de una agregación de toda la tabla sin GROUP BY, que produce una fila de resumen incluso con un conjunto de entrada vacío.
Ordena los grupos de forma explícita
GROUP BY no garantiza ningún orden de salida. Para enumerar primero las regiones con los mayores totales, añade ORDER BY total DESC. El alias total está permitido en ORDER BY; ORDER BY SUM(amount) DESC da la misma ordenación.
Un informe de clientes puede seleccionar los tres totales más altos:
SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer ORDER BY total DESC, customer LIMIT 3;
Devuelve Chen 350, Ana 165 y Ben 140. La segunda clave de ordenación, customer, da a los totales empatados un orden reproducible. LIMIT 3 devuelve solo tres filas; no conserva todos los empates en el límite. SQL Server expresa este límite con SELECT TOP 3, mientras que Oracle admite FETCH FIRST 3 ROWS ONLY.
Al ordenar las etiquetas de categoría de forma ascendente, SQLite normalmente coloca NULL al principio y PostgreSQL lo coloca al final. Especifica la ordenación deseada cuando la posición sea relevante.
Comprueba la columna de agrupación
SELECT DISTINCT region FROM orders y SELECT region FROM orders GROUP BY region devuelven las mismas etiquetas de región distintas, incluido NULL. Utiliza la agrupación cuando también necesites una medida para cada etiqueta.
Agrupar por el valor único order_id da ocho grupos de una fila cada uno. Todos los recuentos son uno, y cada total de importes equivale al importe original. Para un informe regional, ese resultado indica que la columna de agrupación es demasiado detallada.
Puntos clave
- Indica qué representa una fila de salida antes de elegir
GROUP BY. - Todos los valores NULL de agrupación forman un grupo.
- Utiliza
ORDER BYpara establecer el orden del resultado y una segunda clave para resolver empates. - Agrupar por una clave única de fila deja grupos de una fila.
2.2 Aplica la regla que determina qué puede mostrar una consulta agrupada
Un informe agrupado tiene que reunir muchas filas de entrada en una fila de resultado. Por tanto, cada valor mostrado necesita un significado claro para todo el grupo. Por eso SQL restringe las columnas que puedes seleccionar.
Sigue la regla de agrupación compatible con distintas bases de datos
Un elemento de un SELECT agrupado debe ser una columna de agrupación, una expresión construida a partir de columnas de agrupación, una función de agregación o una constante. Considera:
SELECT region, customer, COUNT(*) FROM orders GROUP BY region;
East contiene Ana, Ana y Dara. El grupo tiene una región y un recuento, pero dos nombres de cliente diferentes. La consulta no ha indicado qué cliente debe mostrar el único resultado de East. PostgreSQL rechaza la columna customer sin agrupar.
El mismo problema aparece sin GROUP BY: SELECT customer, SUM(amount) FROM orders combina un total de toda la tabla con un nombre individual. El total no tiene una única etiqueta de cliente.
Corrige la consulta para que responda la pregunta
Hay tres correcciones útiles, cada una con un significado diferente:
- Para obtener una fila por región, elimina
customer:SELECT region, COUNT(*) FROM orders GROUP BY region;. - Para obtener una fila por región y cliente, agrupa por ambos:
SELECT region, customer, COUNT(*) FROM orders GROUP BY region, customer;. - Para obtener el número de clientes por región, aplica una función de agregación a los nombres:
SELECT region, COUNT(DISTINCT customer) AS customers FROM orders GROUP BY region;.
La última consulta muestra dos clientes en East y uno en cada uno de los demás grupos de región. Añadir una columna a GROUP BY puede cambiar el nivel de detalle del informe, así que elige la corrección según la pregunta, no solo según el mensaje de error.
Una columna de agrupación puede omitirse de SELECT. SELECT COUNT(*) FROM orders GROUP BY region; es válida y devuelve cuatro recuentos: tres, dos, dos y uno, sin un orden garantizado. Es difícil utilizar esas cifras sin sus etiquetas de región.
Aplica la regla más allá de SELECT
Un ORDER BY customer agrupado presenta el mismo problema al agrupar solo por región: ¿qué cliente debe determinar la posición de East? Las condiciones HAVING de una consulta agrupada también deben describir un grupo completo. Utiliza en ellas columnas agrupadas o expresiones de agregación.
Reconoce el comportamiento permisivo de algunas bases de datos
SQLite acepta una columna sin agrupar ni agregar, una columna seleccionada que no está agrupada ni se utiliza en una función de agregación. Toma un valor de una fila de entrada del grupo. Un resultado aparentemente correcto, como «Ana» junto a East, no significa que Ana represente todos los pedidos de esa región.
Con exactamente una función de agregación incorporada MIN o MAX, SQLite toma los valores sin agrupar ni agregar de una fila que contiene el extremo. Los empates y la presencia de varias funciones de extremos hacen incierta la fila seleccionada. Este atajo es específico de esa base de datos. Ordenar las filas originales es más claro cuando quieres un pedido con un importe extremo.
El modo predeterminado ONLY_FULL_GROUP_BY de MySQL rechaza los valores sin agrupar que el grupo no determina. ANY_VALUE(customer) permite explícitamente un valor arbitrario, pero no encuentra el cliente asociado a un total elegido. SQL Server y Oracle también rechazan las columnas ordinarias sin agrupar.
PostgreSQL y MySQL reconocen una excepción para la clave primaria: agrupar por la clave primaria de una tabla identifica una sola fila, por lo que sus demás columnas quedan determinadas. SELECT order_id, customer, SUM(amount) FROM orders GROUP BY order_id funciona en PostgreSQL. Incluir en GROUP BY todas las columnas mostradas sin agregar sigue siendo el enfoque compatible con distintas bases de datos.
Puntos clave
- Cada valor mostrado debe describir el grupo completo.
- Eliminar una columna, agrupar por ella o aplicarle una función de agregación responde preguntas diferentes.
- La regla de agrupación también se aplica a
HAVINGyORDER BYen consultas agrupadas. - Las columnas sin agrupar ni agregar que acepta SQLite pueden ocultar un informe incorrecto.
- Una clave primaria agrupada determina las demás columnas de su fila.
2.3 Agrupa por varias columnas y por valores calculados
Algunos informes necesitan una combinación de categorías o una categoría calculada a partir de cada fila. SQL puede agrupar por varias columnas o por una expresión. La decisión importante sigue siendo qué representa una fila de salida.
Agrupa por una combinación
GROUP BY region, customer reúne filas solo cuando coinciden ambos valores. En la tabla de pedidos, ejecuta:
SELECT region, customer, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region, customer ORDER BY region, customer;
Los resultados son East/Ana: dos pedidos, 165; East/Dara: uno, 95; North/Chen: dos, 350; West/Ben: dos, 140; y NULL/Eli: uno, 30. Los dos resultados de East suman el total regional de 260.
Agrupar por customer, region forma las mismas combinaciones. El orden de las columnas en GROUP BY no ordena la salida. El ORDER BY separado de arriba elige cómo mostrarla, según la posición predeterminada de NULL en cada base de datos.
Solo aparecen las combinaciones presentes en los datos de entrada. No hay una fila West/Ana con un recuento de cero. La agrupación resume filas existentes; no genera todos los emparejamientos posibles de etiquetas de categoría.
Añade detalle solo cuando sea necesario
Añadir una columna divide un grupo solo si sus filas contienen valores diferentes en esa columna. Aquí, agrupar solo por cliente ya da cinco grupos. Añadir la región sigue dando cinco, porque cada cliente tiene un solo valor de región. Añadir order_date a un informe regional crea grupos menores para las distintas fechas y cambia la pregunta que se responde.
Agrupa fechas por año y mes
En SQLite, utiliza strftime('%Y-%m', order_date) para crear una etiqueta como «2026-02»:
SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY strftime('%Y-%m', order_date) ORDER BY month;
Enero tiene dos pedidos que suman 200, febrero tiene tres que suman 305 y marzo tiene tres que suman 275. En PostgreSQL, sustituye las dos apariciones de strftime('%Y-%m', order_date) por to_char(order_date, 'YYYY-MM') para una columna DATE.
Agrupar solo por el número de mes combina el mismo mes de distintos años. Enero de 2025 y enero de 2026 se convertirían en un grupo. Mantener el año en la expresión de agrupación conserva separados los meses de cada año.
Repetir la expresión en GROUP BY hace explícita la agrupación. SQLite, PostgreSQL y MySQL también aceptan el alias de salida, como GROUP BY month; SQL Server no acepta ahí un alias de SELECT del mismo nivel.
Crea categorías con CASE
Una expresión CASE puede asignar una etiqueta a cada pedido antes de agrupar:
SELECT CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END AS size, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END;
La categoría large contiene 120, 200 y 150: tres pedidos que suman 470. La categoría small contiene cinco pedidos que suman 310. El umbral es inclusivo, por lo que un importe de exactamente 100 pertenece a «large». La misma expresión CASE aparece en la presentación y en la agrupación para que ambas utilicen la misma definición de categoría.
Puntos clave
- Varias columnas de agrupación identifican combinaciones que aparecen en los datos.
- Añadir una columna solo divide los grupos en los que esa columna varía.
- Incluye el año además del mes para separar los meses de cada año.
- Utiliza la misma expresión de categoría en la etiqueta seleccionada y en la agrupación.
GROUP BYno crea combinaciones ausentes con recuentos de cero.- El orden de las columnas de agrupación no controla el orden de salida.
3Filtra resultados agrupados con HAVING
El filtrado puede cambiar las filas utilizadas en un cálculo o decidir qué resúmenes terminados aparecen en un informe. Esas decisiones responden preguntas diferentes. Utilizarás HAVING para conservar grupos según su recuento, total o promedio, y después lo combinarás con WHERE sin cambiar el significado previsto. Seguir el orden lógico de una consulta facilita colocar cada condición y predecir el resultado antes de ejecutar SQL.
3.1 Conserva los grupos que cumplen una condición
HAVING comprueba los grupos después de calcular sus funciones de agregación. Utilízalo para una petición como «regiones con ventas totales superiores a 200». La condición describe cada total regional, no un pedido individual.
Primero calcula, después conserva los grupos
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region HAVING SUM(amount) > 200;
Antes de HAVING, los totales regionales son East 260, North 350, West 140 y NULL 30. La condición conserva East con tres pedidos y North con dos. Elimina los otros dos grupos del resultado; no elimina pedidos concretos del interior de East o North.
En SQL escrito, coloca HAVING después de GROUP BY y antes de ORDER BY. La ordenación se aplica después a los grupos que han superado la condición.
Filtra por medidas que no muestras
SELECT region FROM orders GROUP BY region HAVING COUNT(*) >= 2; devuelve East, North y West. La base de datos puede contar las filas de un grupo para decidir si cumple la condición sin mostrar ese recuento. HAVING y SELECT no necesitan listas de funciones de agregación idénticas.
Puedes combinar condiciones de grupo. HAVING COUNT(*) >= 2 AND AVG(amount) > 80 conserva East y North. East tiene tres pedidos y un promedio aproximado de 86,67; North tiene dos y un promedio de 175. West tiene suficientes pedidos, pero su promedio es solo 70. Deben cumplirse ambas condiciones porque están unidas con AND; OR permitiría que se cumpliera cualquiera de las dos.
Encuentra valores repetidos
Agrupar y contar también permite encontrar duplicados:
SELECT customer, COUNT(*) AS orders FROM orders GROUP BY customer HAVING COUNT(*) > 1;
Ana, Ben y Chen tienen dos pedidos cada uno y cumplen la condición. Dara y Eli tienen uno y no la cumplen. Para encontrar valores de correo electrónico repetidos en una tabla de clientes, el mismo patrón agrupa por email y conserva los recuentos superiores a uno. El recuento es el número de registros que comparten ese valor.
Utiliza la expresión que necesita la condición
Repite la función de agregación en HAVING: HAVING SUM(amount) > 200. PostgreSQL y SQL estándar no permiten el alias de salida total en esa condición del mismo nivel, aunque SQLite y MySQL sí lo permiten. Un alias es válido en un ORDER BY total DESC posterior.
Un valor redondeado mostrado y el valor comprobado pueden diferir. El promedio exacto de East es 260 dividido entre tres. Si seleccionas ROUND(AVG(amount), 2) pero escribes HAVING AVG(amount) > 86.67, East se elimina: su promedio sin redondear es inferior a 86,67. North permanece. La condición utiliza exactamente la expresión escrita en HAVING. Solo HAVING ROUND(AVG(amount), 2) ... comprobaría el valor redondeado.
Filtra el único grupo global
HAVING también puede funcionar sin un GROUP BY explícito. SELECT COUNT(*) FROM orders HAVING COUNT(*) > 5; trata los ocho pedidos como un grupo, supera la comprobación y devuelve una fila que contiene ocho. Sustituir la condición por COUNT(*) > 10 no devuelve filas, en lugar de devolver una fila que contenga cero.
PostgreSQL admite este patrón, al igual que SQLite desde la versión 3.39.0. En una instalación anterior de SQLite, una consulta que utiliza HAVING necesita un GROUP BY explícito.
Puntos clave
HAVINGconserva o elimina grupos ya calculados.- Una función de agregación de
HAVINGno tiene que aparecer enSELECT. - Combina condiciones de grupo con
AND,ORyNOT. - Repite las expresiones de agregación en
HAVINGpara obtener consultas compatibles con distintas bases de datos. - Una condición comprueba su propia expresión, que puede estar sin redondear.
3.2 Elige entre WHERE y HAVING
Una condición corresponde al punto en el que existe lo que describe. Los pedidos individuales existen antes de la agrupación. Un total regional existe solo después de agrupar y sumar los pedidos.
Sigue el orden lógico
SQL se escribe como SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. Para razonar sobre el resultado, sigue este orden lógico:
FROMaporta las filas.WHEREconserva las filas que cumplen la condición.GROUP BYforma grupos y las funciones de agregación calculan sus medidas.HAVINGconserva los grupos que cumplen la condición.SELECTproduce los valores de salida;DISTINCTelimina las filas de salida duplicadas si se solicita.ORDER BYordena el resultado yLIMITconserva el número de filas solicitado.
La base de datos puede organizar su ejecución interna de otra manera.
Coloca cada condición en su nivel
| Petición | Cláusula |
|---|---|
Pedidos con amount >= 60 | WHERE |
| Pedidos en un intervalo de fechas determinado | WHERE |
Regiones con SUM(amount) > 200 | HAVING |
| Clientes con más de un pedido | HAVING COUNT(*) > 1 |
WHERE SUM(amount) > 200 falla porque el total aún no existe en la etapa de filtrado de filas. Una condición de fila como region = 'East' puede resolverse antes de agrupar y corresponde a WHERE.
Recorre ambos filtros
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE amount >= 60 GROUP BY region HAVING SUM(amount) > 200;
Primero elimina los pedidos de 45 y 30. East contiene ahora 120 y 95, North contiene 200 y 150, y West contiene 80 y 60. Después calcula los totales de 215, 350 y 140. Por último, conserva los totales superiores a 200. La salida es East con dos pedidos y 215, y North con dos y 350. La región NULL no tiene filas restantes, por lo que nunca forma un grupo.
No cambies la pregunta al mover un filtro
«Para cada región, calcula el promedio solo de los pedidos de 60 o más» utiliza WHERE amount >= 60. El promedio de East pasa a ser 107,5 a partir de 120 y 95.
HAVING MIN(amount) >= 60 pide las regiones en las que todos los importes que no son NULL alcanzan el umbral. East se elimina porque su mínimo es 45; North y West permanecen con sus pedidos originales. Mover la comprobación cambió el significado: de seleccionar pedidos individuales a aceptar o rechazar regiones completas.
Para este informe regional, region <> 'West' da el mismo resultado en WHERE o en HAVING: East y North permanecen, y el grupo NULL tampoco supera la comparación. WHERE expresa la restricción de filas directamente y la aplica antes de agrupar. Para conservar también las regiones ausentes, la condición necesita un OR region IS NULL explícito.
Los alias de SELECT no están disponibles en las cláusulas anteriores WHERE y HAVING en PostgreSQL. SQLite permite un uso más amplio de alias, pero escribir la columna o expresión de entrada completa deja clara la etapa prevista.
Puntos clave
WHEREcambia los valores de entrada de las funciones de agregación;HAVINGfiltra sus resultados.- Coloca en
HAVINGlas condiciones sobre el recuento, total o promedio de un grupo. - Al predecir un resultado, sigue el filtrado de filas antes de la agrupación.
- Una comprobación del mínimo de un grupo puede eliminar el grupo completo.
4Calcula resultados exactos y correctamente redondeados
Una consulta puede elegir las filas correctas y aun así perder la parte fraccionaria de su respuesta. Los tipos numéricos controlan la división y los resultados de agregación, mientras que el redondeo controla cuánta precisión muestras. Conservarás los decimales durante los cálculos, elegirás un tratamiento adecuado para un denominador vacío y redondearás solo la medida final. La misma expresión breve puede comportarse de forma diferente entre bases de datos, por lo que se señala cada diferencia relevante.
4.1 Evita la división entera en promedios y porcentajes
Dividir dos valores enteros puede descartar la fracción antes incluso de mostrar la respuesta. Esto importa cuando construyes una media o un porcentaje a partir de totales y recuentos.
Asegúrate de tener un operando decimal antes de dividir
En SQLite y PostgreSQL, 7 / 2 devuelve 3. Con valores de entrada enteros, SUM(quantity) / COUNT(*) sobre la tabla de pedidos devuelve 2: 19 artículos divididos entre ocho pedidos pierden su parte fraccionaria. En PostgreSQL, SUM de una columna INTEGER devuelve BIGINT, que aquí sigue utilizando división entera.
Escribe 1.0 * SUM(quantity) / COUNT(*) para obtener 2,375 en ambos motores. Multiplicar por 1,0 crea un operando decimal antes de la división. SUM(quantity) / COUNT(*) * 1.0 da 2,0 porque la división ya ha descartado la fracción. Las operaciones con la misma precedencia se evalúan de izquierda a derecha.
Para esta tabla, AVG(quantity) da directamente 2,375 en SQLite y PostgreSQL. La fórmula manual importa cuando necesitas un denominador diferente o un porcentaje.
Calcula un porcentaje
Tres de los ocho pedidos tienen importes de al menos 100. El recuento de esos pedidos dividido entre el recuento de todos los pedidos mide su proporción. Multiplica por 100,0:
SELECT 100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*) AS pct_large FROM orders;
El resultado es 37,5. Utilizar el entero 100 produce en cambio 37 en SQLite y en la división entre recuentos enteros de PostgreSQL. Redondear después solo cambiaría cómo se muestra 37.
Una consulta de toda la tabla puede no tener filas que coincidan. NULLIF(COUNT(*), 0) devuelve NULL cuando el recuento es cero, por lo que 100.0 * COUNT(discount) / NULLIF(COUNT(*), 0) devuelve NULL para un conjunto de entrada vacío. Un denominador cero sin protección produce un error en PostgreSQL; SQLite devuelve NULL. Una proporción NULL puede representar claramente que «no hay pedidos que medir».
Comprueba la base de datos y el tipo de entrada
| Base de datos | Comportamiento que debes tener en cuenta |
|---|---|
| SQLite | La división entera trunca; AVG devuelve coma flotante. |
| PostgreSQL | La división entera trunca; AVG de una entrada entera o NUMERIC devuelve NUMERIC. |
| SQL Server | La división entera trunca; AVG de una entrada entera devuelve un entero. |
| MySQL y Oracle | / conserva el resultado fraccionario para operandos enteros. |
En SQL Server, utiliza AVG(quantity * 1.0) o convierte los valores de entrada a DECIMAL antes de calcular el promedio. En PostgreSQL, SUM de una columna BIGINT devuelve NUMERIC, por lo que su división no tiene por qué comportarse como SUM de una columna INTEGER. MySQL devuelve DECIMAL para las sumas de valores de entrada enteros.
Una conversión de tipo también puede crear el operando decimal necesario: utiliza CAST(SUM(quantity) AS REAL) en SQLite o CAST(SUM(quantity) AS NUMERIC) en PostgreSQL. La conversión a NUMERIC de SQLite puede conservar un entero, por lo que esa conversión por sí sola no garantiza una división decimal.
Distingue los decimales exactos de las aproximaciones
Los tipos de coma flotante almacenan aproximaciones binarias. NUMERIC y DECIMAL de PostgreSQL admiten valores decimales exactos; las sumas de coma flotante pueden mostrar pequeñas anomalías como 0,30000000000000004. La afinidad NUMERIC de SQLite no proporciona almacenamiento decimal exacto. Para obtener totales monetarios exactos allí, almacena céntimos como enteros, súmalos y divide entre 100,0 para mostrarlos.
Puntos clave
- Crea un operando decimal antes de dividir totales o recuentos enteros.
- Multiplicar después de una división entera no puede recuperar las cifras perdidas.
- Utiliza
NULLIFpara gestionar un denominador cero. - Los tipos de resultado de las funciones de agregación dependen tanto del motor como del tipo de entrada.
- La afinidad
NUMERICde SQLite no proporciona almacenamiento decimal exacto. - SQL Server necesita valores de entrada decimales para obtener un promedio fraccionario de enteros.
4.2 Redondea los resultados de agregación
El redondeo determina cuántas cifras muestra un resultado. Conserva el cálculo completo hasta el último paso para que las decisiones de presentación no cambien la medida que estás calculando.
Redondea un resultado de agregación
ROUND(x, n) redondea a n cifras después de la coma decimal. ROUND(x) redondea a un número entero. Por ejemplo, ROUND(3.14159, 2) es 3,14.
SELECT region, ROUND(AVG(amount), 2) AS avg_amount FROM orders GROUP BY region; da East 86,67, North 175, West 70 y región NULL 30. SQLite puede mostrar 175,0, mientras que el resultado NUMERIC de PostgreSQL muestra 175,00. Ambos representan el mismo número. Redondear un número y dar formato a una etiqueta de texto de anchura fija son tareas diferentes.
Redondea después de sumar o calcular el promedio
Para tres cargos de 0,44, suma primero para obtener 1,32 y después redondea a un decimal para obtener 1,3. ROUND(SUM(fee), 1) sigue esa secuencia. SUM(ROUND(fee, 1)) redondea cada cargo a 0,4 y después los suma, lo que da 1,2. El redondeo anticipado ha cambiado el total.
Del mismo modo, ROUND(100 * 1 / 3, 1) da 33,0 en SQLite y PostgreSQL porque la división entera ya ha producido 33. ROUND(100.0 * 1 / 3, 1) conserva la fracción y da 33,3. Elige el tipo de cálculo antes de redondear.
Los porcentajes redondeados pueden no sumar 100 %. Tres partes iguales pueden mostrarse como 33,3 % cada una y sumar 99,9 %. Las proporciones originales siguen cubriendo el total. Recalcular una parte arbitraria para forzar el total mostrado cambia el significado de esa cifra.
Utiliza un tipo de entrada compatible
PostgreSQL admite ROUND(value, n) con dos argumentos para NUMERIC. Si temp es DOUBLE PRECISION, escribe ROUND(CAST(AVG(temp) AS NUMERIC), 2). El promedio de 20,5; 21,25 y 19,0 es 20,25, y la conversión te permite utilizar el redondeo con dos argumentos. Con amount de tipo entero, el promedio de PostgreSQL ya es NUMERIC, por lo que no hace falta convertirlo.
Para valores NUMERIC exactos de PostgreSQL, los casos situados justo a mitad se redondean alejándose de cero: 2,5 se convierte en 3 y -2,5 se convierte en -3. SQLite también da 3,0 y -3,0 para estos ejemplos. El redondeo de coma flotante de PostgreSQL depende de la plataforma; es habitual redondear al número par más cercano. La aproximación binaria también puede situar un decimal justo por debajo del punto medio previsto. No utilices un empate concreto de coma flotante como regla general para la aritmética decimal exacta.
Observa otras dos diferencias entre dialectos
PostgreSQL, MySQL, SQL Server y Oracle utilizan un número negativo de posiciones decimales para redondear a la izquierda de la coma decimal. ROUND(1234.5, -2) da 1200. SQLite trata un segundo argumento negativo como cero y da 1235,0. Para redondear a centenas en SQLite, utiliza ROUND(x / 100.0) * 100.
La conversión a entero también depende de la base de datos: SQLite elimina la parte fraccionaria, por lo que 2,9 se convierte en 2; PostgreSQL lo redondea a 3. Utiliza ROUND cuando quieras redondear. En cambio, TRUNC(x, n) de PostgreSQL elimina cifras: TRUNC(2.97, 1) es 2,9, mientras que redondearlo a un decimal da 3,0.
Puntos clave
- Redondea el resultado de agregación después de completar su cálculo.
- El redondeo no puede corregir una división entera anterior.
- Los porcentajes redondeados pueden sumar 99,9 % o 100,1 %.
- Convierte un promedio de coma flotante de PostgreSQL a
NUMERICpara utilizarROUNDcon dos argumentos. - Las posiciones negativas de redondeo y las conversiones a entero difieren entre bases de datos.
5Responde preguntas de negocio con consultas de resumen
Los informes de negocio suelen necesitar varias medidas de la misma población: todos los pedidos, los pedidos grandes y la proporción de pedidos grandes. La agregación condicional mantiene esas medidas una al lado de la otra. Después construirás un informe completo a partir de su pregunta, comprobarás totales y categorías ausentes, y utilizarás un segundo paso de agregación cuando la pregunta trate sobre clientes u otros grupos en lugar de pedidos individuales.
5.1 Cuenta y suma según una condición con CASE
La agregación condicional permite que distintas medidas utilicen distintas aportaciones manteniendo el mismo conjunto global de filas. Una expresión CASE decide qué aporta cada fila a un recuento o una suma.
Cuenta las filas que cumplen la condición
COUNT(CASE WHEN amount >= 100 THEN 1 END) cuenta los pedidos de al menos 100. La expresión devuelve 1 cuando se cumple la condición y NULL para las demás filas porque no tiene ELSE. COUNT omite esos valores NULL, por lo que quedan tres coincidencias en la tabla de pedidos.
SUM(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) cuenta las coincidencias sumando unos y ceros. Cuando existen filas de entrada, da el mismo recuento. COUNT(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) no lo hace: ni 1 ni 0 son NULL, por lo que cuenta los ocho pedidos.
Suma los importes que cumplen la condición
Para obtener un total condicional, devuelve el propio importe:
SELECT region, COUNT(*) AS orders, COUNT(CASE WHEN amount >= 100 THEN 1 END) AS large_orders, SUM(CASE WHEN amount >= 100 THEN amount ELSE 0 END) AS large_total FROM orders GROUP BY region;
East tiene tres pedidos, un pedido grande y un total de pedidos grandes de 120. North tiene dos pedidos, ambos grandes, que suman 350. West tiene dos pedidos, ningún pedido grande y un total de pedidos grandes de cero. El grupo de región NULL tiene un pedido y ceros en ambas medidas de pedidos grandes.
La salida conserva West porque sus filas de entrada siguen existiendo. Añadir WHERE amount >= 100 eliminaría las filas de West antes de agrupar, por lo que West desaparecería. Ese filtro también haría que COUNT(*) contara solo los pedidos grandes, perdiendo la comparación con todos los pedidos.
Utiliza el denominador correcto
Dentro de cada región, calcula el porcentaje de pedidos grandes con ROUND(100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*), 1) AS pct_large. East da 33,3; North 100,0; West 0,0 y el grupo NULL 0,0. Cada denominador es el recuento de pedidos de ese grupo, no el recuento de ocho de toda la tabla.
Para un informe sin agrupar que pueda no tener filas, protege el denominador con NULLIF(COUNT(*), 0). Un recuento sobre un conjunto de entrada vacío es cero, pero un porcentaje de una población vacía no tiene denominador.
Crea varias columnas de categoría
Un único resultado puede mostrar un recuento por región:
SELECT COUNT(CASE WHEN region = 'East' THEN 1 END) AS east, COUNT(CASE WHEN region = 'West' THEN 1 END) AS west, COUNT(CASE WHEN region = 'North' THEN 1 END) AS north FROM orders;
Los recuentos son tres, dos y dos. El pedido de Eli no cumple ninguna de estas condiciones de región con nombre. Añade COUNT(CASE WHEN region IS NULL THEN 1 END) para contar el único pedido sin región. Comparar una región NULL con un nombre no produce una condición verdadera.
Reconoce sintaxis alternativas
PostgreSQL y SQLite desde la versión 3.30.0 admiten COUNT(*) FILTER (WHERE amount >= 100). El filtro se aplica a esa función de agregación, por lo que un COUNT(*) contiguo sin filtro sigue contando todos los pedidos. MySQL y SQL Server no admiten esta sintaxis FILTER de agregación; la forma con CASE funciona en ambos.
SQLite y MySQL también permiten SUM(amount >= 100) porque las comparaciones producen valores de verdad numéricos. PostgreSQL rechaza SUM de valores booleanos. Utiliza la forma con CASE cuando una consulta deba funcionar en todos estos motores.
Puntos clave
- Coloca condiciones dentro de las funciones de agregación para mantener juntas las medidas de distintos subconjuntos.
COUNT(CASE ... THEN 1 END)omite las filas que no cumplen la condición.ELSE 0funciona para una suma condicional, pero hace que un recuento condicional también cuente las filas que no cumplen la condición.- Un porcentaje dentro de un grupo utiliza la población de ese grupo como denominador.
- Un
FILTERde agregación cambia solo los valores de entrada de esa función de agregación. - Utiliza
IS NULLpara contar por separado las categorías ausentes.
5.2 Construye y comprueba una consulta de resumen a partir de una pregunta
Una consulta de resumen empieza con una pregunta sobre una población con un nivel de detalle concreto. Traduce esas decisiones antes de escribir SQL y después comprueba que la salida siga respondiendo la pregunta original.
Construye el informe en orden
Plantea: «Para cada mes de 2026 con al menos tres pedidos, ¿cuántos pedidos se hicieron y cuál fue el importe medio, con dos decimales?».
- Las medidas son
COUNT(*)yAVG(amount). - La granularidad, o significado de una fila de resultado, es un mes del calendario.
- La condición de fila conserva las fechas de 2026.
- La condición de grupo exige al menos tres pedidos.
- La salida debe ordenarse por mes, con el promedio redondeado para mostrarlo.
En SQLite:
SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, ROUND(AVG(amount), 2) AS avg_amount FROM orders WHERE order_date >= '2026-01-01' AND order_date < '2027-01-01' GROUP BY strftime('%Y-%m', order_date) HAVING COUNT(*) >= 3 ORDER BY month;
Para valores de fecha de PostgreSQL, sustituye la expresión de mes en ambos lugares por to_char(order_date, 'YYYY-MM'). El intervalo de fechas incluye el inicio de 2026 y excluye el inicio de 2027.
Enero tiene dos pedidos y no cumple la condición de grupo. Febrero tiene tres pedidos que suman 305, con un promedio de 101,67. Marzo tiene tres que suman 275, con un promedio de 91,67. Los grupos que permanecen representan seis pedidos, no ocho, porque HAVING ha eliminado enero.
Comprueba antes de eliminar grupos con el filtro
Ejecuta primero el informe sin HAVING. Los recuentos de todos los grupos deben sumar el recuento de filas bajo el mismo filtro WHERE, y los totales deben sumar el total sin agrupar. Aquí esas comprobaciones dan ocho y 780. No compares los totales de los grupos conservados con todo el conjunto de entrada después de excluir algunos grupos.
Busca un grupo NULL, examina el orden de los resultados y vuelve a calcular un grupo filtrando la tabla original. Para East, WHERE region = 'East' debe dar tres pedidos que sumen 260. Una discrepancia puede revelar una columna de agrupación adicional, un filtro de filas mal colocado o una expresión que se haya convertido en NULL.
Distingue el promedio por pedido del promedio por cliente
AVG(amount) es 97,5 por pedido. El gasto medio por cliente pide una unidad diferente: los cinco totales de cliente son 165, 140, 350, 95 y 30. Su promedio es 156.
Calcúlalo en dos etapas:
SELECT AVG(total) AS avg_customer_total FROM (SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer) AS per_customer;
La consulta interna crea una fila por cliente. La consulta externa calcula el promedio de esas filas, de modo que cada cliente aporta una vez. Si todos los clientes están identificados, 1.0 * SUM(amount) / COUNT(DISTINCT customer) da el mismo 156. Cuando los números de pedidos son desiguales, calcular el promedio de los importes de pedido es un cálculo diferente.
Resume los propios grupos
Para contar los clientes con más de un pedido, primero enuméralos y después cuenta sus filas:
SELECT COUNT(*) FROM (SELECT customer FROM orders GROUP BY customer HAVING COUNT(*) > 1) AS repeat_customers;
La respuesta es tres. Anidar directamente funciones de agregación, como en MAX(AVG(amount)) en un mismo nivel de consulta, falla en SQLite y PostgreSQL. Para encontrar la región con el promedio más alto, ordena los promedios agrupados: ORDER BY AVG(amount) DESC LIMIT 1 devuelve North con 175. Oracle también admite funciones de grupo anidadas, pero un nivel de consulta separado hace explícitos los dos cálculos. Comprueba los empates cuando un informe pida un resultado máximo.
Puntos clave
- Elige las medidas, la granularidad, las condiciones de fila y las condiciones de grupo a partir de la pregunta.
- Comprueba los recuentos y totales de los grupos antes de eliminar grupos con
HAVING. - Un promedio por cliente necesita los totales de cliente como valores de entrada.
- Utiliza una consulta interna agrupada y una función de agregación externa para resumir grupos.
Ejemplos de Agregación y agrupación en SQL
1Convierte filas de pedidos en cifras de resumen fiables
13 pasos
- 1IntroducciónLee la pregunta del informe
Una persona responsable quiere un total de pedidos, un recuento de clientes y un descuento medio. Cada uno parece una cifra sencilla, pero utiliza los datos de entrada de forma diferente. Cada uno es un agregado, que convierte muchas filas en un único valor, y una elección equivocada da una cifra engañosa. Construiremos esas medidas a partir de los ocho pedidos: primero combinaremos los importes, después elegiremos qué contar y, por último, decidiremos cómo cambia NULL el promedio. Sigue preguntándote qué aporta una fila de entrada al resultado.
- 2ExplicaciónCombina los importes
Una función de agregación combina valores de muchas filas en un resumen.
SUM(amount)suma los importes,AVG(amount)calcula su media yMIN(amount)yMAX(amount)localizan los extremos. SinGROUP BY, todos los pedidos que cumplen las condiciones forman un grupo. Puedes seleccionar varias funciones de agregación juntas porque cada una describe ese mismo grupo de filas de entrada. - 3EjemploCalcula un resumen completo
Los importes de los pedidos son 120, 80, 45, 200, 60, 95, 150 y 30. Suman 780. Dividir ese total entre ocho da un promedio de 97,5; el mínimo es 30 y el máximo es 200.
SELECT SUM(amount) AS total, AVG(amount) AS mean_amount, MIN(amount) AS low, MAX(amount) AS high FROM orders;La salida es una fila con cuatro medidas etiquetadas.
- 4EjemploElige los datos de entrada antes de sumar
Ahora pregunta solo por East.
WHERE region = 'East'conserva los importes 120, 45 y 95 antes de que se ejecute la función de agregación.SELECT SUM(amount) AS total FROM orders WHERE region = 'East';La salida es 260. Las otras regiones no aportan nada porque sus pedidos no cumplen la condición de fila. Un filtro sobre las filas de entrada cambia el propio total, no solo la etiqueta que muestra.
- 5DesafíoMantén cada cantidad con su precio
Una tabla de ventas tiene dos filas: cantidad 4 a un precio unitario de 6 y cantidad 2 a un precio unitario de 9. ¿Qué devuelve
SUM(quantity * unit_price)y por qué es diferente multiplicar las dos sumas?---reveal---
Los ingresos de las filas son 24 y 18, por lo que la suma es 42. Multiplicar las sumas da seis por 15, es decir, 90, porque ya no empareja cada cantidad con el precio de su propia fila.
- 6ExplicaciónCuenta registros o clientes
Los pedidos indican Ana, Ben, Ana, Chen, Ben, Dara, Chen y Eli.
COUNT(customer)cuenta ocho nombres registrados, incluidas las apariciones repetidas.COUNT(DISTINCT customer)cuenta cinco nombres diferentes.La redacción determina cuál corresponde: un recuento de pedidos necesita filas, mientras que un recuento de clientes necesita clientes distintos. Los nombres iguales en pedidos separados son repeticiones esperadas, no clientes adicionales.
- 7EjemploCuenta la categoría ausente
La columna region tiene ocho filas, pero solo siete valores registrados.
COUNT(*)es ocho,COUNT(region)es siete yCOUNT(DISTINCT region)es tres.Restar el recuento de valores registrados del recuento de filas da una región ausente. Observa que una lista de regiones distintas también incluiría una fila NULL; el recuento de valores distintos ignora ese NULL en lugar de tratarlo como una cuarta región con nombre.
- 8DesafíoElige el recuento correcto
Una columna coupon contiene NULL, 0, 8, 8 y 0. ¿Qué valores devuelven
COUNT(*),COUNT(coupon)yCOUNT(DISTINCT coupon), en ese orden?---reveal---
Devuelven cinco, cuatro y dos. Hay cinco filas, cuatro valores registrados y dos valores registrados diferentes, 0 y 8. Los ceros registrados cuentan; NULL no entra en ninguno de los dos recuentos de columna.
- 9ExplicaciónExcluye una calificación desconocida
Considera las calificaciones 80, NULL, 70 y 90. Las calificaciones registradas suman 240.
AVG(score)divide entre las tres calificaciones registradas y devuelve 80.No divide entre las cuatro filas: una calificación ausente no es un cero conocido. Si el valor ausente representa un examen al que no se presentó y que debe calificarse con cero, el cálculo previsto cambia a
AVG(COALESCE(score, 0)), que da 60. - 10EjemploColoca el valor predeterminado en la etapa correcta
Falta el descuento en cuatro pedidos. En
SUM(amount - discount), cada una de esas expresiones de fila se convierte en NULL, por lo que solo contribuyen las otras cuatro. Sus importes netos suman 345.Si un valor ausente significa que no hay descuento, utiliza
SUM(amount - COALESCE(discount, 0)). Así contribuyen los ocho pedidos y el total es 750.COALESCEalrededor de la suma ya calculada no puede recuperar las aportaciones de las filas omitidas. - 11DesafíoGestiona un grupo sin valores conocidos
Una consulta conserva tres filas cuyos importes son todos NULL. ¿Qué devuelven
COUNT(*),COUNT(amount)ySUM(amount)?---reveal---
Devuelven tres, cero y NULL. Existen filas, pero no hay importes registrados que contar o sumar. Un conjunto de entrada vacío también daría una suma NULL, pero su recuento de filas sería cero. Utiliza
COALESCE(SUM(amount), 0)solo cuando el informe deba mostrar ese total ausente como cero. - 12DesafíoComprueba un cálculo y su población
Cuatro registros de servicio tienen cargos de 20, 30, 40 y 50, con abonos de 2, NULL, 0 y NULL. Un abono ausente significa que no hay abono. ¿Qué cargo neto total y qué recuento de abonos registrados debe mostrar el informe?
---reveal---
Utiliza
SUM(charge - COALESCE(credit, 0))para obtener un total neto de 138, yCOUNT(credit)para obtener dos abonos registrados. El abono de cero cuenta como registrado; sustituir NULL dentro de la suma conserva los cuatro cargos. - 13RepasoMantén la medida vinculada a sus datos de entrada
Elige la función de agregación a partir de la pregunta y después sigue los valores que entran en ella. Los recuentos distinguen filas, valores registrados y valores diferentes. Para los promedios y la aritmética de filas, comprueba qué elimina NULL y si una sustitución tiene un significado real. Cuando una respuesta resulte sorprendente, examina las filas que permanecen y sus aportaciones antes de cambiar el SQL.
2Construye un informe con el nivel de detalle adecuado
14 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDecide qué representa una fila del resultado
- 2ExplicaciónReúne filas por región
- 3EjemploMantén visible el grupo NULL
- 4ConsejoOrdena antes de conservar las primeras filas
- 5DesafíoPredice cuántos grupos quedan
- 6ExplicaciónExplica por qué un nombre es ambiguo
- 7EjemploCorrige el informe a partir de su pregunta
- 8ConsejoReconoce un resultado permisivo
- 9DesafíoElige una corrección con sentido
- 10EjemploDivide un grupo por un segundo valor
- 11ExplicaciónCrea una etiqueta de mes del calendario
- 12DesafíoEncuentra la expresión de agrupación
- 13DesafíoComprueba la granularidad y las etiquetas del informe
- 14RepasoInterpreta cada fila como un grupo
3Coloca filtros antes o después de la agregación
10 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDistingue la población de la selección
- 2ExplicaciónComprueba el grupo ya calculado
- 3EjemploUtiliza un recuento sin mostrarlo
- 4DesafíoComprueba el valor real que se compara
- 5ExplicaciónSigue las etapas lógicas del resultado
- 6EjemploElimina primero los pedidos pequeños
- 7EjemploDespués elimina los totales de grupo pequeños
- 8DesafíoDiagnostica una pregunta que ha cambiado
- 9DesafíoCombina restricciones de fila y de grupo
- 10RepasoDeja que la condición indique su etapa
4Conserva las fracciones y redondea el resultado final
11 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónSepara el cálculo de la presentación
- 2EjemploEncuentra dónde desaparece la fracción
- 3ExplicaciónIntroduce el decimal al principio
- 4ConsejoProtege un denominador vacío
- 5DesafíoCorrige una expresión de porcentaje
- 6ExplicaciónRedondea el promedio ya calculado
- 7EjemploObserva cómo el redondeo anticipado cambia un total
- 8DesafíoComprueba una diferencia entre dialectos
- 9ConexiónElige el tipo para importes exactos
- 10DesafíoComprueba el tipo antes de redondear
- 11RepasoSigue el número por cada etapa
5Construye y comprueba un resumen de negocio
13 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónMantén juntos todos los pedidos y los pedidos seleccionados
- 2ExplicaciónHaz que las filas que no cumplen la condición aporten NULL
- 3EjemploMantén disponible el grupo completo
- 4EjemploSuma el importe o suma uno
- 5DesafíoConserva el denominador de un subconjunto
- 6ExplicaciónTraduce la redacción de negocio
- 7EjemploConstruye el resultado mensual
- 8ConsejoComprueba antes de ocultar grupos
- 9ExplicaciónCambia la unidad de entrada de un promedio
- 10EjemploLee los dos niveles de consulta
- 11DesafíoElige la unidad correcta para el promedio
- 12DesafíoCuenta solo los grupos de clientes que cumplen las condiciones
- 13RepasoComprueba la población y la granularidad
Ejercicios de Agregación y agrupación en SQL
Set 1: Elige la población y el detalle del informe10 Preguntas de Práctica
Pregunta 1 de 10
COUNT(priority)?Mostrar respuestaOcultar respuesta
COUNT(priority) cuenta los tres valores registrados: cero y las dos apariciones de 2. El cero es un valor conocido, por lo que cuenta. Contar cinco utilizaría el recuento de filas, mientras que contar dos eliminaría las repeticiones además de NULL.Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
hours > 120 descartaría aportaciones menores aunque pertenecieran a un consultor cuyo total conjunto supera 120.Pregunta 3 de 10
MIN(delivery_date) y MAX(delivery_date), en ese orden?Mostrar respuestaOcultar respuesta
Pregunta 4 de 10
SELECT COUNT(*) FROM (SELECT DISTINCT city, agent FROM visits) AS pairs?Mostrar respuestaOcultar respuesta
Pregunta 5 de 10
SUM(cost - credit) y el coste neto total previsto, en ese orden?Mostrar respuestaOcultar respuesta
Pregunta 6 de 10
ORDER BY total DESC, customer ASC LIMIT 2, suponiendo que los nombres se ordenan alfabéticamente?Mostrar respuestaOcultar respuesta
Pregunta 7 de 10
ROUND(SUM(fee), 1) y SUM(ROUND(fee, 1)), en ese orden, si se ignoran las pequeñas anomalías de presentación de coma flotante?Mostrar respuestaOcultar respuesta
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Pregunta 9 de 10
SELECT training FROM roster GROUP BY training HAVING COUNT(*) >= 3?Mostrar respuestaOcultar respuesta
Pregunta 10 de 10
WHERE amount >= 60 GROUP BY team HAVING AVG(amount) > 80, ¿qué queda?Mostrar respuestaOcultar respuesta
Set 2: Interpreta recuentos, grupos y cálculos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
SUM(distance)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
COUNT(CASE WHEN status = 'closed' THEN 1 ELSE 0 END)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
AVG(delay)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
SELECT department, COUNT(*) FROM shifts GROUP BY department?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
FROM parts GROUP BY category?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
paid_on con registros de 2024 a 2026. ¿Qué expresión de agrupación mantiene separado cada mes del calendario?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
HAVING SUM(amount) > 200?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
ORDER BY supplier. Las categorías tienen varios proveedores. ¿Cómo puede mostrar primero las categorías de mayor coste sin cambiar su granularidad?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
SUM(quantity) / COUNT(*) * 1.0?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
ROUND(SUM(fee), 1), pero conserva el grupo global solo con HAVING SUM(fee) >= 0.8. ¿Qué resultado devuelve?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Combina valores ausentes, tipos y grupos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
SELECT 17 / 5 en SQLite?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
SELECT SUM(quantity * price) FROM stock WHERE department = 'A'?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
COUNT(DISTINCT region)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
jobs cumple state = 'queued'. ¿Qué devuelve SELECT team, COALESCE(SUM(hours), 0) FROM jobs WHERE state = 'queued' GROUP BY team?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
WHERE area IS NOT NULL GROUP BY area, ¿cuáles son los recuentos de los grupos?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END. ¿Cuántos grupos resultan?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Diagnostica y completa informes10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
WHERE amount >= 30 con agrupar todas las filas y utilizar HAVING MIN(amount) >= 30. ¿Qué promedios aparecen?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
temperature es DOUBLE PRECISION. ¿Cómo redondeas su promedio a dos decimales?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
COUNT(*) FILTER (WHERE paid = 1) aparece junto a COUNT(*) en una consulta agrupada sin cláusula WHERE. ¿Qué restringe el filtro?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
COUNT(*), COUNT(value) y MAX(value), en ese orden?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
WHERE zone <> 'West'. ¿Qué grupos de zona pueden permanecer?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Agregación condicional
Agrupación por varias columnas
Alias de SELECT
ORDER BY, pero cuyos usos en otros lugares dependen del dialecto.ORDER BY total, pero necesita que se escriba la expresión de agregación completa en un HAVING del mismo nivel.AVG
AVG(amount) da 97,5 para ocho pedidos cuyos importes suman 780, y mide el importe medio por pedido.C
CAST
REAL en SQLite permite la división decimal, mientras que una conversión a NUMERIC puede mantener como entero un valor sin parte fraccionaria.Categoría definida con CASE
CASE, que puede convertirse en la base de un informe agrupado.amount >= 100 coloca un pedido de exactamente 100 en la categoría etiquetada como «large».Clave de año y mes
COALESCE
COALESCE(SUM(amount), 0) muestra cero cuando un conjunto de entrada vacío produciría un total NULL.Columna de agrupación
Columna sin agrupar ni agregar
Combinación distinta
Comparación sin redondeo
HAVING AVG(amount) >= 86.67 si su valor exacto es menor.Conciliación de resultados
HAVING para que los grupos excluidos no expliquen una diferencia entre el informe y el total de entrada.Condición de fila
amount >= 60 puede conservar un pedido de East y eliminar otro antes de que exista ningún resumen regional.Condición de grupo
Conjunto de entrada con todos los valores NULL
COUNT(x) es cero.COUNT(*) cuatro y COUNT(discount) cero cuando un filtro selecciona solo esos pedidos.Conjunto de entrada vacío
WHERE no encuentra registros que coincidan.COUNT(*)
COUNT(*) igual a ocho aunque un pedido no tenga una región registrada.COUNT(column)
COUNT(discount) incluye un pedido con descuento cero, pero excluye uno con descuento NULL.COUNT(DISTINCT column)
COUNT(DISTINCT customer) para obtener el número de clientes identificados, aunque algunos hagan varios pedidos.Criterio de desempate
ORDER BY total DESC, customer da a los totales de cliente empatados un orden estable antes de aplicar un límite.D
Dependencia funcional
Detección de duplicados
HAVING COUNT(*) > 1 identifica a los clientes que aparecen en varios registros de pedido.Diferencia por redondeo
DISTINCT
SUM(DISTINCT quantity) suma cada valor de cantidad una vez, por lo que puede excluir del total ventas reales con cantidades repetidas.División entera
E
Expresión de agregación
SUM(amount - discount) evalúa la resta en cada fila antes de sumar los resultados que no son NULL.Expresión de agrupación
CASE.F
FILTER de una función de agregación
Función de agregación
SUM(amount) para convertir muchos importes de pedido en un total para el periodo seleccionado.G
Granularidad
GROUP BY
GROUP BY region permite que una misma consulta calcule un recuento de pedidos y un total de importes separados para cada región.Grupo de valores NULL
H
HAVING
HAVING SUM(amount) > 200 conserva las regiones según su total, sin eliminar pedidos pequeños de los grupos que permanecen.I
Intercalación
MIN sigan siendo las mismas.IS NULL
WHERE region IS NULL selecciona los pedidos cuya región no se ha registrado, como el pedido de un cliente llamado Eli.M
Medida
MIN y MAX
MIN(order_date) encuentra la fecha más temprana cuando la columna contiene fechas o texto de fecha ISO con un formato uniforme.N
NULL
amount - discount sea NULL, lo que provoca que SUM omita el valor calculado de esa fila.NULLIF
NULLIF(COUNT(*), 0) convierte en NULL el denominador de un informe vacío y evita un error de división entre cero en PostgreSQL.NUMERIC y DECIMAL
Número de coma flotante
DOUBLE PRECISION de PostgreSQL puede mostrar 0,30000000000000004 donde la aritmética decimal exacta da 0,3.O
ONLY_FULL_GROUP_BY
Operando decimal
Orden lógico de procesamiento de consultas
WHERE antes de GROUP BY explica por qué eliminar pedidos pequeños cambia el promedio posterior de una región.ORDER BY
ORDER BY total DESC enumera primero los totales de grupo más altos después de calcular cada grupo.P
Porcentaje dentro del grupo
Promedio por cliente
R
Recuento condicional
COUNT.COUNT(CASE WHEN amount >= 100 THEN 1 END) cuenta los pedidos grandes y omite los resultados NULL de las filas que no cumplen la condición.Redondeo final
Regla de agrupación
ROUND
ROUND(AVG(amount), 2) redondea el promedio ya calculado a dos decimales y mantiene intacto el cálculo anterior.S
SUM
SUM(quantity * unit_price) suma los ingresos de las filas después de multiplicar cada cantidad por su precio correspondiente.T
Tabla derivada
FROM, que permite que una segunda consulta resuma las filas creadas por la primera.Total condicional
CASE que devuelve cero para las demás.CASE el propio importe que cumple la condición; devolver 1 contaría pedidos en su lugar.Truncamiento
TRUNC y SQLite lo aplica al convertir a entero.TRUNC(2.97, 1) da 2,9 en PostgreSQL, mientras que ROUND(2.97, 1) da 3,0 para ese decimal exacto.V
Valor exactamente a mitad entre dos resultados de redondeo
NUMERIC en PostgreSQL lleva 2,5 a 3 y -2,5 a -3, alejando de cero ambos empates.W
WHERE
WHERE antes de calcular los totales mensuales.- 1Modelo relacional
- 2Consultas con SELECT
- 3Columnas calculadas en SQL
- 4Agregación y agrupación en SQL
- 5JOIN SQL
- 6Crear y modificar tablas de base de datos
Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.