Cuando empecé a usar SQL para SEO, fue como ponerse lentes por primera vez. De repente, los datos que antes veía borrosos en dashboards genéricos se volvieron nítidos, específicos y accionables.
No necesitas ser desarrollador para usar SQL. Si puedes escribir una fórmula en Google Sheets, puedes escribir una query SQL. Es lógica, no magia. Y el poder que te da para analizar datos de SEO es enorme.
1. Top keywords con oportunidad de CTR
Esta query encuentra keywords donde tienes buenas posiciones pero CTR bajo — oportunidades para mejorar titles y metas:
SELECT
query,
SUM(impressions) AS total_impressions,
SUM(clicks) AS total_clicks,
ROUND(SUM(clicks) / SUM(impressions) * 100, 2) AS ctr,
ROUND(SUM(position * impressions) / SUM(impressions), 1) AS avg_position
FROM `project.dataset.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
GROUP BY query
HAVING total_impressions > 100 AND avg_position <= 10 AND ctr < 3
ORDER BY total_impressions DESC
LIMIT 50;
Lo que hace: busca queries en top 10 con más de 100 impresiones pero CTR menor a 3%. Esas son URLs donde estás visible pero no convences al usuario de hacer clic.
2. Páginas que perdieron tráfico mes a mes
WITH current_month AS (
SELECT url, SUM(clicks) AS clicks_now
FROM `project.dataset.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
GROUP BY url
),
previous_month AS (
SELECT url, SUM(clicks) AS clicks_before
FROM `project.dataset.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 56 DAY) AND DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY)
GROUP BY url
)
SELECT
c.url,
p.clicks_before,
c.clicks_now,
c.clicks_now - p.clicks_before AS diff
FROM current_month c
JOIN previous_month p ON c.url = p.url
WHERE p.clicks_before > 10
ORDER BY diff ASC
LIMIT 30;
Esta query compara los clics de cada URL en los últimos 28 días versus los 28 anteriores. Las que más cayeron aparecen primero. Es tu alerta temprana de contenido que necesita atención.
3. Canibalización de keywords
SELECT
query,
COUNT(DISTINCT url) AS urls_ranking,
ARRAY_AGG(DISTINCT url LIMIT 5) AS sample_urls,
SUM(impressions) AS total_impressions
FROM `project.dataset.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
GROUP BY query
HAVING urls_ranking > 1 AND total_impressions > 50
ORDER BY total_impressions DESC
LIMIT 50;
Cuando varias URLs de tu sitio compiten por la misma keyword, Google no sabe cuál priorizar. Esta query detecta esas keywords con múltiples URLs rankeando. Tú decides cuál consolidar.
4. Distribución de posiciones por directorio
SELECT
REGEXP_EXTRACT(url, r'https?://[^/]+(/[^/]+/)') AS directory,
COUNT(DISTINCT url) AS pages,
ROUND(AVG(position), 1) AS avg_position,
SUM(clicks) AS total_clicks
FROM `project.dataset.searchdata_site_impression`
WHERE data_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND CURRENT_DATE()
GROUP BY directory
HAVING pages > 3
ORDER BY total_clicks DESC;
Perfecta para sitios grandes. Te muestra qué secciones de tu sitio tienen mejor rendimiento orgánico. Si /blog/ tiene posición promedio de 15 pero /guias/ está en 5, sabes dónde enfocar tu esfuerzo.
5. Content freshness — últimas fechas de indexación
SELECT
url,
MAX(data_date) AS last_seen,
SUM(impressions) AS total_impressions,
DATE_DIFF(CURRENT_DATE(), MAX(data_date), DAY) AS days_since_seen
FROM `project.dataset.searchdata_site_impression`
WHERE impressions > 0
GROUP BY url
HAVING days_since_seen > 30
ORDER BY total_impressions DESC
LIMIT 50;
Esta query encuentra URLs que dejaron de aparecer en Search Console hace más de 30 días. Si antes tenían impresiones y ahora no, puede ser un problema de indexación, una penalización o contenido caducado.
¿Dónde ejecutar estas queries?
La forma más directa es con BigQuery. Si tienes Search Console conectado a BigQuery (es gratis hasta cierto volumen), puedes ejecutar estas queries directamente. También funcionan adaptadas en cualquier base de datos donde tengas datos exportados.
Si no tienes BigQuery configurado, empieza por ahí. La conexión GSC → BigQuery toma 10 minutos y te abre un mundo de posibilidades para análisis de SEO con SQL.