Conceptos clave

GROUP BY y ORDER BY sin dolor de cabeza

5 min de lectura

GROUP BY: agrupar para resumir

GROUP BY divide las filas en grupos basándose en los valores de una o más columnas. Después de agrupar, las funciones de agregación (COUNT, SUM, AVG) calculan un resultado por cada grupo en lugar de un total general.

Sin GROUP BY:

-- Un solo total para todo el sitio
SELECT COUNT(DISTINCT user_pseudo_id) AS usuarios_totales
FROM tabla_eventos
WHERE traffic_source.medium = 'organic'
-- Resultado: 1 fila con el total

Con GROUP BY:

-- Un total por cada dispositivo
SELECT
  device.category AS dispositivo,
  COUNT(DISTINCT user_pseudo_id) AS usuarios
FROM tabla_eventos
WHERE traffic_source.medium = 'organic'
GROUP BY dispositivo
-- Resultado: 3 filas (desktop, mobile, tablet)

La regla fundamental: toda columna que aparece en el SELECT y que no está dentro de una función de agregación debe estar en el GROUP BY. Si se incluye dispositivo en el SELECT, debe estar en el GROUP BY. Si se olvida, BigQuery devuelve un error.

Agrupar por múltiples columnas

Se pueden agrupar datos por dos o más dimensiones simultáneamente. Cada combinación única genera una fila en los resultados:

-- Sesiones por dispositivo Y país
SELECT
  device.category AS dispositivo,
  geo.country AS pais,
  COUNT(DISTINCT session_id) AS sesiones
FROM tabla_eventos
WHERE traffic_source.medium = 'organic'
GROUP BY dispositivo, pais
ORDER BY sesiones DESC

Si hay 3 tipos de dispositivo y 20 países, el resultado puede tener hasta 60 filas (3 x 20), una por cada combinación. En la práctica suele ser menos, porque no todas las combinaciones existen en los datos.

HAVING: filtrar después de agrupar

WHERE filtra filas antes de la agregación. HAVING filtra después. Esto es importante porque permite excluir grupos con datos insuficientes:

-- Solo keywords con al menos 100 impresiones
SELECT
  query AS keyword,
  SUM(clicks) AS clics,
  SUM(impressions) AS impresiones
FROM `your-project.searchconsole.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
GROUP BY keyword
HAVING impresiones >= 100
ORDER BY clics DESC

No se puede usar WHERE impresiones >= 100 porque impresiones es un resultado de SUM, que no existe hasta después de la agregación. HAVING actúa sobre los resultados ya agregados.

Un uso muy común en SEO: excluir páginas o keywords con poco volumen para que los promedios y porcentajes sean estadísticamente significativos, como en la query de engagement rate por landing page.

ORDER BY: ordenar los resultados

ORDER BY define el orden en que aparecen las filas en los resultados. Sin esta cláusula, el orden es arbitrario e impredecible.

-- Ordenar de mayor a menor (descendente)
ORDER BY sesiones DESC

-- Ordenar de menor a mayor (ascendente, valor por defecto)
ORDER BY posicion_media ASC

-- Ordenar por múltiples columnas
ORDER BY pais ASC, sesiones DESC

La dirección por defecto es ASC (ascendente). DESC (descendente) se usa explícitamente cuando se quieren ver primero los valores más altos (más clics, más sesiones, más impresiones). Para métricas donde lo bajo es lo que interesa (posición media baja, páginas con menos tráfico), se usa ASC.

Cuando se ordena por múltiples columnas, la primera columna es el criterio principal. La segunda se aplica solo cuando hay empates en la primera.

LIMIT: restringir la cantidad de resultados

LIMIT se usa junto con ORDER BY para obtener los N primeros o últimos resultados:

-- Top 50 keywords por clics
SELECT query, SUM(clicks) AS clics
FROM gsc_data
GROUP BY query
ORDER BY clics DESC
LIMIT 50

Casi todas las queries del catálogo de Queryteca terminan con ORDER BY ... LIMIT N. Es una combinación fundamental que convierte una lista desordenada de miles de filas en un ranking accionable de las N más relevantes.

El orden de ejecución importa

SQL no se ejecuta en el orden en que se escribe. El orden real de procesamiento es:

  1. FROM: identifica la tabla.
  2. WHERE: filtra filas antes de agrupar.
  3. GROUP BY: agrupa las filas que pasaron el filtro.
  4. HAVING: filtra grupos después de agregar.
  5. SELECT: elige las columnas y calcula las funciones.
  6. ORDER BY: ordena los resultados finales.
  7. LIMIT: recorta los N primeros.

Conocer este orden ayuda a entender por qué ciertas cosas no funcionan. Por ejemplo, no se puede usar un alias definido en el SELECT dentro del WHERE (porque WHERE se ejecuta antes), pero sí dentro del ORDER BY (que se ejecuta después). BigQuery es flexible con esto y permite usar aliases en HAVING y ORDER BY.

Ejemplo completo

Una consulta que combina todas las cláusulas vistas hasta ahora, similar a la query de top keywords por clics:

SELECT
  query AS keyword,
  SUM(clicks) AS clics,
  SUM(impressions) AS impresiones,
  ROUND(SAFE_DIVIDE(SUM(clicks), SUM(impressions)) * 100, 2) AS ctr,
  ROUND(SUM(sum_top_position + impressions) / SUM(impressions), 2) AS posicion
FROM `your-project.searchconsole.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
  AND search_type = 'WEB'
GROUP BY keyword
HAVING impresiones >= 50
ORDER BY clics DESC
LIMIT 100

Siguiente paso

Con las cláusulas de agregación y ordenamiento dominadas, el siguiente desafío frecuente en BigQuery es el manejo de fechas: _TABLE_SUFFIX, FORMAT_DATE, DATE_SUB y compañía. Las fechas son la parte que más errores genera al principio, pero con las funciones correctas se manejan con facilidad.

Queries para practicar

Principiante

URLs con más clics totales en GSC

Identifica las páginas que reciben más clics desde los resultados de búsqueda de Google. Permite conocer las URLs más valiosas del sitio desde la perspectiva de SEO.

Principiante

Performance por país en GSC

Desglosa el rendimiento de búsqueda por país. Permite identificar mercados geográficos donde el sitio tiene presencia y detectar oportunidades de expansión internacional.

¿Listo para practicar? Explora el catálogo de queries

Ver catálogo