JOINs explicados para SEO (cruzar GA4 con GSC)
5 min de lecturaEl problema que resuelven los JOINs
Los datos de SEO están repartidos en múltiples fuentes. Google Search Console almacena keywords, clics, impresiones y posiciones. GA4 almacena sesiones, engagement, conversiones y comportamiento del usuario. Cada fuente tiene información valiosa, pero por separado ninguna responde la pregunta más importante: qué keywords generan valor real en el sitio.
Los JOIN en SQL permiten combinar datos de dos o más tablas en una sola consulta. La conexión se establece a través de un campo común: en el caso de SEO, ese campo suele ser la URL.
Anatomía de un JOIN
La estructura básica es:
SELECT
tabla_a.columna1,
tabla_b.columna2
FROM
tabla_a
JOIN tabla_b ON tabla_a.campo_comun = tabla_b.campo_comun
La cláusula ON define la condición de unión: qué campo de la primera tabla debe coincidir con qué campo de la segunda. Solo las filas donde hay coincidencia en ambas tablas aparecen en los resultados (en el caso de INNER JOIN).
INNER JOIN: solo coincidencias
INNER JOIN (o simplemente JOIN) devuelve solo las filas donde hay coincidencia en ambas tablas. Si una URL existe en GSC pero no en GA4, esa fila no aparece. Si existe en GA4 pero no en GSC, tampoco.
-- Cruce básico: keywords de GSC con sesiones de GA4
WITH gsc AS (
SELECT url, query, SUM(clicks) AS clics
FROM `your-project.searchconsole.searchdata_url_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
GROUP BY url, query
),
ga4 AS (
SELECT
REGEXP_EXTRACT(
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'),
r'(https?://[^?#]+)'
) AS url_normalizada,
COUNT(DISTINCT user_pseudo_id) AS usuarios
FROM `your-project.analytics_XXXXXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY))
AND FORMAT_DATE('%Y%m%d', CURRENT_DATE())
AND traffic_source.medium = 'organic'
GROUP BY url_normalizada
)
SELECT gsc.query, gsc.url, gsc.clics, ga4.usuarios
FROM gsc
INNER JOIN ga4 ON gsc.url = ga4.url_normalizada
ORDER BY gsc.clics DESC
LIMIT 50
Este patrón de CTEs separados (uno para cada fuente) seguidos de un JOIN es exactamente el que usan las queries de cruce del catálogo de Queryteca.
LEFT JOIN: todas las de la izquierda, coincidan o no
LEFT JOIN devuelve todas las filas de la tabla izquierda (la primera), y las completa con datos de la tabla derecha cuando hay coincidencia. Si no hay coincidencia, las columnas de la tabla derecha muestran NULL.
Es la opción correcta cuando se quieren ver todas las URLs de una fuente, incluyendo aquellas que no tienen datos en la otra fuente:
-- Todas las URLs de GSC, con datos de GA4 si existen
SELECT
gsc.url,
gsc.clics,
IFNULL(ga4.sesiones, 0) AS sesiones_ga4
FROM gsc
LEFT JOIN ga4 ON gsc.url = ga4.url_normalizada
Las URLs de GSC que no tienen tráfico registrado en GA4 aparecerán con sesiones_ga4 = 0 (gracias a IFNULL que convierte NULL en 0). Esto es útil para detectar páginas zombi: URLs indexadas en Google que no generan tráfico real.
FULL OUTER JOIN: todo de ambas tablas
FULL OUTER JOIN devuelve todas las filas de ambas tablas, tengan o no coincidencia. Es útil para comparaciones completas, como la variación porcentual entre periodos:
-- URLs que existen en periodo actual, anterior, o ambos
SELECT
COALESCE(actual.url, anterior.url) AS url,
IFNULL(anterior.clics, 0) AS clics_antes,
IFNULL(actual.clics, 0) AS clics_ahora
FROM periodo_actual actual
FULL OUTER JOIN periodo_anterior anterior ON actual.url = anterior.url
COALESCE toma el primer valor no nulo: si la URL existe en el periodo actual la toma de ahí, si no la toma del anterior.
El problema del matching de URLs
El punto más delicado de los cruces entre GSC y GA4 es que las URLs pueden no coincidir exactamente. GSC almacena URLs limpias (https://ejemplo.com/pagina), mientras que GA4 almacena la URL completa que el navegador registra, incluyendo parámetros de query string (https://ejemplo.com/pagina?utm_source=twitter&ref=header).
Por eso todas las queries de cruce del catálogo normalizan la URL de GA4 antes de hacer el JOIN:
-- Extraer solo scheme + host + path, sin parámetros
REGEXP_EXTRACT(page_location, r'(https?://[^?#]+)') AS url_normalizada
Sin esta normalización, muchos cruces fallarían silenciosamente: las URLs simplemente no coincidirían y los resultados estarían incompletos sin que el error fuera evidente.
Otro aspecto relevante es el rendimiento. Los JOINs sobre tablas muy grandes pueden consumir recursos significativos en BigQuery. Una buena práctica consiste en aplicar filtros (WHERE) dentro de cada subconsulta antes de realizar el cruce, de modo que las tablas intermedias sean lo más pequeñas posible. Reducir el volumen de datos antes del JOIN no solo acelera la ejecución, sino que también disminuye el consumo de cuota de procesamiento.
Cuándo usar cada tipo de JOIN
- INNER JOIN: cuando solo interesan las URLs que existen en ambas fuentes. Ejemplo: keywords que generan conversiones.
- LEFT JOIN: cuando se parte de una fuente como base y se enriquece con datos de la otra. Ejemplo: top URLs por conversión (todas las de GSC, con conversiones de GA4 si existen).
- FULL OUTER JOIN: cuando se comparan dos conjuntos completos. Ejemplo: comparativa de periodos.
Siguiente paso
Los JOINs combinan tablas, pero para obtener resúmenes útiles se necesitan funciones de agregación. COUNT, SUM y AVG convierten miles de filas en métricas accionables como totales de clics, promedios de posición o tasas de conversión.
Queries para practicar
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.
Top 50 landing pages orgánicas por sesiones
Identifica las 50 páginas de entrada con mayor volumen de sesiones orgánicas. Útil para priorizar esfuerzos de optimización en las URLs que más tráfico captan.
Performance por dispositivo (mobile, desktop, tablet)
Compara el rendimiento de búsqueda por tipo de dispositivo. Permite detectar diferencias de posicionamiento o CTR entre mobile y desktop que indiquen problemas de UX o indexación.
¿Listo para practicar? Explora el catálogo de queries
Ver catálogo