Publicado por Lino Uruñuela el 19 de marzo de 2025
Los grandes modelos de lenguaje (LLMs) como los disponibles por OpenAI o Google se pueden ejecutar en tu propio ordenador sin apenas consumir recursos, ya que realmente se procesan en las máquinas de estos proveedores. Esto, en principio, no sería un impedimento para ejecutar LLMs en tu ordenador, pero son de pago y, para el volumen de datos con el que suelo trabajar, no me resulta rentable.
Aunque el precio por token de entrada/salida es aparentemente bajo, deja de serlo si tienes que solicitar decenas o cientos de millones... Por ejemplo, algunas propiedades de Search Console pueden tener millones de keywords únicas. Y no solo eso, si combinas ciertos datos como keyword, title y algo más en una página que tenga unas 100.000 URLs, el número de tokens que querrás procesar comienza a crecer rápidamente.
Cuando se trata de un funcionamiento en producción, puede tener mucho sentido usar los modelos de pago de los grandes proveedores, dependerá del problema que estés resolviendo y, sobre todo, del valor que aporte la solución. Si eres una empresa de seguros y un LLM bien ejecutado puede resolver un porcentaje de las consultas que hacen los usuarios, posiblemente puedas (y debas) considerar estos modelos.
Pero si eres alguien como yo, que está todo el día investigando con grandes volúmenes de datos para explorar nuevas utilidades o funcionalidades que solo voy a usar yo, o por ejemplo, para crear un buscador en tu sitio web o un buscador semántico en los contenidos de vídeos, posiblemente no te salga a cuenta.
Dicho esto, el otro día probé el nuevo modelo de Mistral y, sinceramente, me ha encantado. Funciona relativamente bien, al menos en el primer caso de uso que estoy creando, que es mostrar datos, por ejemplo de Search Console, haciéndole preguntas en lenguaje natural.
De momento, he creado un script básico que se ejecuta desde la línea de comandos. Odio los stacks y frameworks, etc., cuando voy a ser yo el único que lo ejecute y use. Soy un poco "hater" de los frameworks, sean de lo que sean, normalmente para mis casos de uso solo añaden complejidad.
Para ejecutar los LLMs que mi ordenador es capaz de procesar uso llm
(desarrollado por Simon Willison, si no le sigues, ¡deberías!), ya que es fácil, tiene actualizados todos los modelos y me ocupa mucho menos espacio que cuando instalo LLMs con Ollama, puede que por mi propio desconocimiento...
Por si quieres probarlo,aquí tienes las instrucciones, solo con 1 línea ya lo tendrás instalado y luego, por ejemplo, este sería el comando para descargar la lista de modelos de Mistral:
$ llm install llm-mistral
Ahora vamos al lío :), vamos a ejecutar el modelo 'mistral/mistral-small-2503', por ejemplo, le solicitamos la lista de modelos de Nike en la última década.
$ llm -m mistral/mistral-small-2503 "lista los modelos de zapatillas Nike en los últimos 10 años"
Lo que nos devuelve la lista de zapatillas Nike en formato Markdown
1. **Nike Air Max 270** (2018) - Conocida por su gran unidad Air Max para máxima amortiguación.
2. **Nike Air VaporMax** (2017) - Introduce una unidad Air completa sin soporte adicional, ofreciendo una sensación de flotación.
3. **Nike Air Zoom Pegasus 36** (2019) - Parte de la popular serie Pegasus, conocida por su comodidad y rendimiento.
4. **Nike Air Force 1** (Versiones actualizadas) - Un clásico que ha sido reimaginado con nuevas tecnologías y diseños.
5. **Nike Air Max 720** (2016) - Ofrece una unidad Air Max de 360 grados para una amortiguación completa.
[...recortado por extensión...]
Ya hemos visto cómo podemos ejecutar fácilmente este modelo de Mistral en nuestro ordenador. Ahora intentaremos ir un poco más allá y nos marcaremos como objetivo poder realizar consultas a Search Console usando lenguaje natural.
Yo proceso los datos de logs, Search Console, Analytics y otras fuentes diariamente. Cada día me descargo a mi BBDD los nuevos datos generados en GSC para todos los proyectos de mis clientes y los uso a menudo para diferentes tareas como análisis profundos, alertas, forecast, etc... Y sí, también porque me gusta, o tengo el síndrome de Diógenes con los datos :).
Vamos a usar la línea de comandos para ejecutar una consulta SQL a la base de datos, que está en mi ordenador. Se podría usar cualquier cliente de bases de datos típico como MySQL, PostgreSQL, DuckDB, ClickHouse, etc. Para este ejemplo, estoy usando ClickHouse.
En este caso, vamos a usar el cliente de ClickHouse para hacer una consulta de prueba:
clickhouse-client -u default --ask-password -q "select now()"
┏━━━━━━━━━━━━━━━━━━━━━┓
┃ now() ┃
┡━━━━━━━━━━━━━━━━━━━━━┩
│ 2025-03-19 11:27:46 │
└─────────────────────┘
Pero también podría hacer una consulta a la base de datos de GSC para contar cuántas filas hay en la tabla.
#A partir de aquí usaré 'sqlCH' en vez de 'clickhouse-client -u default --ask-password'para hacerlo más corto
sqlCH "select count() cnt from default.GSC_ https_MiDominio_dev FORMAT Pretty"
┏━━━━━━━━━━┓
┃ cnt ┃
┡━━━━━━━━━━┩
│ 10648667 │
└──────────┘
Algo crucial es comunicarle al modelo cómo se llaman las tablas, cuáles son las columnas y qué tipo de variables son. Esto lo hago con la SQL "DESCRIBE TABLE", cuyo resultado será intercalado en el prompt que pasaremos al LLM.
sqlCH "DESCRIBE Table default.GSC_ https_MiDominio_dev FORMAT Pretty"
┏━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ name ┃ type ┃ default_type ┃ default_expression ┃ comment ┃ codec_expression ┃ ttl_expression ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
1. │ fecha │ Date │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
2. │ consulta │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
3. │ landing │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
4. │ clicks │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
5. │ impresiones │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
6. │ posicion │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
7. │ ctr │ Float32 │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
8. │ dispositivo │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
9. │ pais │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
10. │ id_cliente │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
11. │ propiedad │ String │ │ │ │ │ │
└─────────────┴─────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
Ahora podemos ir juntando/concatenando las diferentes piezas que tenemos para crear el prompt que enviaremos al modelo, indicándole el nombre de la tabla y luego el resultado de la SQL DESCRIBE. Al final, si os fijáis, añado la consulta que quiero hacer, en este caso: "Genera una SQL que sume el total de clicks en la tabla".
:~$ llm -m mistral/mistral-small-2503 "Este es el esquema de la tabla: \
┏━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ name ┃ type ┃ default_type ┃ default_expression ┃ comment ┃ codec_expression ┃ ttl_expression ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ fecha │ Date │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ consulta │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ landing │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ clicks │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ impresiones │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ posicion │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ ctr │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ dispositivo │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ pais │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ id_cliente │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ propiedad │ String │ │ │ │ │ │
└─────────────┴─────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
Genera una SQL que sume el total de clicks en la tabla"
Esto nos devuelve una SQL que podemos ejecutar en nuestra base de datos para obtener el dato que hemos solicitado.
sql
SELECT SUM(clicks) AS total_clicks
FROM .GSC_https_ MiDominio_dev;
Esta consulta selecciona la suma de la columna clicks y la etiqueta como total_clicks. La tabla .GSC_https_ MiDominio_dev es especificada en la cláusula FROM.
Si necesitas agregar alguna condición, como filtrar por un rango de fechas o algún otro criterio, puedes hacerlo utilizando la cláusula WHERE. Por ejemplo, si quieres sumar los clicks solo para un rango de fechas específico, podrías hacer algo como esto:
sql
SELECT SUM(clicks) AS total_clicks
FROM .GSC_https_ MiDominio_dev
WHERE fecha BETWEEN '2023-01-01' AND '2023-12-31';
Asegúrate de ajustar las fechas y cualquier otra condición según tus necesidades específicas.
Este tipo de consultas SQL las resuelve bastante bien, tampoco tiene mucha ciencia, pero podemos ir bastante más allá.
Para poder aprovechar la SQL que nos facilita Mistral, debemos hacer que el modelo se calle, y que únicamente devuelva la SQL, sin explicaciones ni consejos ni nada, solo la SQL para poder ejecutar la salida del modelo directamente contra la base de datos...
Aquí un consejo importante: utiliza un usuario de la base de datos que solo tenga permisos de lectura, porque nadie te puede asegurar que el LLM no genere accidentalmente un DROP DATABASE....
. En serio, si ejecutas muchas SQL obtenidas de LLMs, será cuestión de estadística que algo así ocurra, o al menos esa es mi hipótesis.
Como un esquema simple, podríamos decir que:
#De momento nuestro prompt está vacío
Texto inicial del prompt: "Eres un asistente de SQL que..."
#El contenido de nuestro prompt ahora es: Eres un asistente de SQL que...
Ejecuto el cliente de la base de datos para obtener el resultado de "DESCRIBE TABLE nombreTabla".
Concateno lo que me devuelve el comando para añadirlo al prompt.
#El contenido de nuestro prompt ahora es:
Eres un asistente de SQL que... . Este es el esquema de la tabla nombreTabla:
┏━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ name ┃ type ┃ default_type ┃ default_expression ┃ comment ┃ codec_expression ┃ ttl_expression ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ fecha │ Date │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ consulta │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ landing │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ clicks │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ impresiones │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ posicion │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ ctr │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ dispositivo │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ pais │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ id_cliente │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ propiedad │ String │ │ │ │ │ │
└─────────────┴─────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
Eres un asistente de SQL que... . Este es el esquema de la tabla nombreTabla:
┏━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
┃ name ┃ type ┃ default_type ┃ default_expression ┃ comment ┃ codec_expression ┃ ttl_expression ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩
│ fecha │ Date │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ consulta │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ landing │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ clicks │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ impresiones │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ posicion │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ ctr │ Float32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ dispositivo │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ pais │ String │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ id_cliente │ UInt32 │ │ │ │ │ │
├─────────────┼─────────┼──────────────┼────────────────────┼─────────┼──────────────────┼────────────────┤
│ propiedad │ String │ │ │ │ │ │
└─────────────┴─────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
Genera una SQL que sume el total de clicks. Devuelve únicamente la SQL completa, sin comentarios adicionales, en texto plano.
Ya tenemos un prompt "completo", que se lo damos al LLM pasándole la información necesaria para comprender los datos y que genera la respuesta, en este caso una SQL que ejecutaremos en nuestra base de datos, en este caso concreto para obtener el número total de clicks.
Va siendo hora de organizar todo esto dentro de un script, porque además veremos cómo podemos ir mejorando/complicando esta pila de ejecución.
Al script que he creado le paso dos argumentos (bueno, tres, pero los últimos son para activar/desactivar determinadas funcionalidades):
Como primer argumento, le paso el nombre de la base de datos y la tabla. En el script, se ejecuta la SQL "DESCRIBE TABLE..." y el resultado se añade a la variable del prompt.
El segundo argumento es la pregunta en sí, en este caso sería: "Genera una SQL que sume el total de clicks. Devuelve únicamente la SQL completa, sin comentarios adicionales, en texto plano."
Con este simple prompt ya creado y guardado en una variable, ejecuto el LLM de Mistral, que me devuelve la SQL a ejecutar y que guardo en otra variable. El siguiente paso simplemente es ejecutar la SQL devuelta por el LLM, ¡y listo!
Pero las cosas no son tan sencillas, ni tan complicadas... Muchas veces falla, usa funciones SQL que no son compatibles con la base de datos que le indicas, o genera la SQL con errores de formato. Sin embargo, es posible corregirlo.
Cuándo la ejecución de la SQL falla podemos volver a pedir al LLM que genere una SQL, pero le añadiremos al prompt la SQL que acabamos de ejecutar y el mensaje de error que ha generado para indicar al LLM que pruebe con otra SQL diferente y teniendo en cuenta el error que había generado.
De esta forma, cuando falla, vuelve a intentarlo teniendo el contexto de los intentos anteriores. En consultas complejas se ve cómo va corrigiendo los errores, por ejemplo, si ha usado una función que ClickHouse no admite, se da cuenta y en el siguiente reintento lo corrige. Si el número de intentos al ejecutar la SQL supera un máximo que defino yo, se para y termina.
Este proceso podríamos repetirlo las veces que quisiéramos con la idea de que alguna acertará, pero la probabilidad de que la SQL genere un resultado correcto intuyo qye será inversamente proporcional al número de intentos...
Por último, si añado como parámetro al script '--explicaSQL=si' cuándo ejecute la SQL correctamente se creará un nuevo prompt con las instrucciones para que el LLM explique la SQL que ha generado resultados.
Aquí dejo una imagen en la que intento representar el flujo de instrucciones que sigue el script
Este script, aunque parezca complejo, es bastante simple, y funciona para muchísimas de las consultas que realizo. Para SQLs con cierto nivel de dificultad, por ejemplo regresiones logísticas o uso de datos de entrenamiento y validación en las propias SQL, si bien no lo hace mal del todo, no te puedes fiar completamente, ya que a veces no realiza bien la "teorización" del problema.
Y aquí dejo el código del script que implementa este proceso.
#!/bin/bash
if [ "$#" -lt 2 ]; then
echo "Uso: $0 '' [--explicaSQL=si]"
exit 1
fi
DB_TABLA="$1"
PROMPT="$2"
MUESTRA_EXPLICACION=0
if [ "$3" = "--explicaSQL=si" ]; then
MUESTRA_EXPLICACION=1
fi
CLICKHOUSE_CLIENT="clickhouse-client -u default --password=MI_PASSWORD!"
intentos=0
max_intentos=15
errores_acumulados=""
mkdir -p logs
LOG_FILE="logs/sqlResultados_log.csv"
if [ ! -f "$LOG_FILE" ]; then
echo "prompt;sql;estado_salida;respuesta;tabla" > "$LOG_FILE"
fi
tabla=$($CLICKHOUSE_CLIENT --query="DESCRIBE TABLE $DB_TABLA" | tr '\n' ' ')
while [ "$intentos" -lt "$max_intentos" ]; do
sqlIA=$(llm -m mistral/mistral-small-2503 "Este es el esquema SQL de ClickHouse para la tabla $DB_TABLA: $tabla. $PROMPT ${errores_acumulados:+Ten en cuenta los siguientes errores generados anteriormente al ejecutar SQLs anteriores: $errores_acumulados} Devuelve únicamente la SQL completa, sin comentarios adicionales, en texto plano." | grep -v '
')
salida=$($CLICKHOUSE_CLIENT -q "$sqlIA" 2>&1)
resultado=$?
if [ "$resultado" -eq 0 ]; then
estado_salida="correcta"
respuesta="$salida"
else
estado_salida="error"
respuesta="$salida"
errores_acumulados+=" | SQL: ${sqlIA//[$'\n'$'\t']/ } Error: ${salida//[$'\n'$'\t']/ }"
fi
echo "\"${PROMPT//\"/\"\"}\";\"${sqlIA//\"/\"\"}\";$estado_salida;\"${respuesta//\"/\"\"}\";$DB_TABLA" >> "$LOG_FILE"
if [ "$resultado" -eq 0 ]; then
echo " SQL ejecutada con éxito:\n$sqlIA\n Resultado:\n$salida"
if [ "$MUESTRA_EXPLICACION" -eq 1 ]; then
explicacion=$(llm -m mistral/mistral-small-2503 "Explica qué hace esta SQL: $sqlIA")
echo -e " Explicación:\n$explicacion"
fi
exit 0
else
intentos=$((intentos+1))
echo -e " Intento $intentos fallido:\n$respuesta"
sleep 1
fi
done
echo " Se han agotado los intentos, no se generó una SQL válida."
exit 1
sqlCHIA3.sh "default.GSC_ https_MiDominio_dev" "Genera una consulta SQL válida para ClickHouse que liste las 10 consultas con más clicks totales desde tres meses antes de la última fecha disponible hasta dicha última fecha, (NO DESDE HOY, TEN EN CUENTA QUE LA ÚLTIMA FECHA EN LA TABLA NO ES LA DE HOY). Las columnas serán exactamente: consulta,totalClicks. Limita los resultados únicamente a las 10 consultas con más clicks totales, añadir al final de la consulta SQL 'FORMAT Markdown'. Usa funciones analíticas o agregadas propias de ClickHouse."
sqlCHIA3.sh "default.GSC_ https_MiDominio_dev" "Genera una consulta SQL válida para ClickHouse que liste las 10 consultas con más clicks totales desde tres meses antes de la última fecha disponible hasta dicha última fecha, (NO DESDE HOY, TEN EN CUENTA QUE LA ÚLTIMA FECHA EN LA TABLA NO ES LA DE HOY). Las columnas serán exactamente: consulta,totalClicks. Limita los resultados únicamente a las 10 consultas con más clicks totales, añadir al final de la consulta SQL 'FORMAT Markdown'. Usa funciones analíticas o agregadas propias de ClickHouse."
sqlCHIA3.sh \
"WA.GSC_ MiDominio_dv" \
"Genera una consulta SQL válida para que devuelva las URLs que más diferencia de clicks hay entre los periodos:
- Periodo 1: desde 2025-02-03 al 2025-02-16
- Periodo 2: desde 2025-01-13 al 2025-01-26
Devolver las columnas:
- landing
- clicks_Periodo_1
- clicks_Periodo_2
- diferencia_clicks_Periodo1_Periodo2
- % de clicks perdidos (cuanto representa frente al total de clicks perdidos de todas las landings), con dos decimales
- % de clicks perdidos acumulado (va sumando cada % de clicks perdidos), con dos decimales
Ordena las URLs en base al total de clicks perdidos (es decir, aquellas cuya diferencia: clicks en Periodo_1 menos clicks en Periodo_2, sea menor).
Limita el número de resultados a 100. Añadir al final de la consulta SQL: 'FORMAT Markdown'."