Las funciones de ventana (Window Functions) son esenciales para análisis modernos: rankings, totales acumulados y comparaciones temporales. Sin embargo, escribir la cláusula: OVER (PARTITION BY ... ORDER BY ... ROWS ...) es propenso a errores de sintaxis y lógica.
¿Por qué luchar con los paréntesis cuando puedes definir la lógica de negocio y dejar que la IA maneje la gramática SQL?
El Prompt Maestro
Para obtener un análisis complejo de ventas, no le pidas a ChatGPT «una query de ventas». Sé un arquitecto. Dale el esquema y pide las métricas exactas.
Copia este prompt:
«Actúa como un experto en PostgreSQL. Tengo dos tablas: sales_reps (id, name, region) y deals (deal_id, rep_id, date, amount, status).
Necesito un reporte analítico de ventas ‘closed_won’ que muestre por cada vendedor y mes:
- El total vendido ese mes.
- El total acumulado anual del vendedor hasta ese mes.
- El ranking del vendedor dentro de su región ese mes (basado en total vendido).
- El crecimiento porcentual respecto al mes anterior (usando
LAG).Usa CTEs para legibilidad y asegúrate de manejar la división por cero si aplica.»
La Respuesta de la IA (Simulada y Optimizada)
La IA generará algo muy similar a esto. Observa la elegancia del uso de CTEs antes de aplicar las funciones ventana.
WITH monthly_sales AS (
-- Paso 1: Agregar ventas por Vendedor y Mes
SELECT
r.name,
r.region,
DATE_TRUNC('month', d.deal_date) AS sales_month,
SUM(d.amount) AS total_monthly
FROM sales_reps r
JOIN deals d ON r.rep_id = d.rep_id
WHERE d.status = 'closed_won'
GROUP BY 1, 2, 3
)
SELECT
name,
region,
TO_CHAR(sales_month, 'YYYY-MM') AS month,
total_monthly,
-- Running Total (Acumulado anual)
SUM(total_monthly) OVER (
PARTITION BY name, DATE_TRUNC('year', sales_month)
ORDER BY sales_month
) AS running_total_yearly,
-- Ranking Regional
RANK() OVER (
PARTITION BY region, sales_month
ORDER BY total_monthly DESC
) AS regional_rank,
-- Crecimiento vs Mes Anterior (Growth MoM)
ROUND(
(total_monthly - LAG(total_monthly) OVER (PARTITION BY name ORDER BY sales_month))
/ NULLIF(LAG(total_monthly) OVER (PARTITION BY name ORDER BY sales_month), 0) * 100
, 2) AS growth_pct
FROM monthly_sales
ORDER BY region, name, sales_month;
Análisis de la respuesta
Aquí es donde dejas de codificar y empiezas a auditar:
- Validación de
PARTITION BY: La IA usóPARTITION BY name, DATE_TRUNC('year'...)para el acumulado. Correcto: queremos que el acumulado se reinicie cada año y sea por persona. - Validación de
RANK: UsóORDER BY total_monthly DESC. Correcto: el que más vende tiene el rango 1.- Ojo: ¿Qué pasa si hay empate?
RANK()salta números (1, 1, 3). Si quieres (1, 1, 2), deberías corregir a la IA y pedirDENSE_RANK().
- Ojo: ¿Qué pasa si hay empate?
- Alucinación Común: A veces la IA olvida el
NULLIFen la división del crecimiento porcentual. Si el mes anterior fue 0, la query fallará. En este caso, el prompt maestro solicitó manejarlo, y la IA cumplió.
Conclusión
Olvídate de memorizar ROWS BETWEEN UNBOUNDED PRECEDING: entiende la ventana y deja que el asistente escriba el SQL por ti.
Visualiza este ejercicio en db-fiddle.com