English

Manual de campo · trampas de SQL

¿Por qué WHERE no puede filtrar el resultado de una window function?

El WHERE se evalúa antes de que existan las columnas calculadas con OVER. Para filtrar por una window function hace falta QUALIFY, o envolver la consulta en un CTE y filtrar desde fuera.

Cuándo aparece

Cualquier filtro sobre lag(), row_number(), sum() OVER (…) u otra window function: 'la fila anterior a menos de 10 minutos', 'sólo la primera de cada grupo', 'sólo las filas con ranking 1'.

Ejemplo

Mal: DuckDB lo rechaza, no compila

SELECT tarjeta, momento,
       lag(momento) OVER (PARTITION BY tarjeta ORDER BY momento) AS previo
FROM validaciones
WHERE date_diff('minute', lag(momento) OVER (PARTITION BY tarjeta ORDER BY momento), momento) < 10;
-- error: no se puede llamar a una window function dentro del WHERE

Bien: QUALIFY filtra después de calcular la ventana

SELECT tarjeta, momento,
       lag(momento) OVER (PARTITION BY tarjeta ORDER BY momento) AS previo
FROM validaciones
QUALIFY date_diff('minute', previo, momento) < 10;

El orden real de ejecución de una consulta es FROM → WHERE → GROUP BY → HAVING → *ventanas* → QUALIFY → SELECT. Las window functions se calculan después del WHERE, así que un WHERE no puede referirse a lag(...) OVER (...): la columna todavía no existe en ese punto, y DuckDB lo rechaza con un error, no con un resultado equivocado. QUALIFY es exactamente el HAVING de las ventanas: corre después de calcularlas y puede usar su resultado directamente, incluso el alias que le diste en el SELECT. En motores sin QUALIFY (casi todos salvo DuckDB, Snowflake y BigQuery) el equivalente es envolver la consulta en un CTE y poner el filtro en el WHERE de la consulta exterior, donde la columna calculada ya existe como una columna normal.

Esta trampa está escondida en un caso de verdad, con datos de verdad.

Jugar el caso 1 gratis →

Trampas relacionadas