Ahora nuestra misión es ir un paso más allá y aprender a usar funciones de ventana para analizar datos temporales. ¿Preparadx? Espero que tengas una taza de café a mano, porque esto se va a poner interesante.
Entonces, como siempre, primero respondemos a la pregunta principal: ¿para qué necesitamos funciones de ventana (LEAD(), LAG())? Imagina que trabajas con datos temporales, ya sean logs de eventos, horas de trabajo, series temporales o cualquier cosa donde el orden de los eventos importa.
Por ejemplo, quieres:
- Saber cuándo ocurrió el siguiente evento después del actual.
- Calcular la diferencia de tiempo entre el evento actual y el anterior.
- Ordenar los datos y calcular la diferencia entre registros.
Aquí es donde entran en juego dos funciones geniales: LEAD() y LAG(). Te permiten sacar datos de la fila anterior o siguiente dentro de una ventana definida. Es como si tuvieras un libro mágico donde puedes mirar la siguiente página sin pasar la actual.
LEAD() y LAG(): sintaxis y principios básicos
Ambas funciones usan una sintaxis parecida:
LEAD(column_name, [offset], [default_value]) OVER (PARTITION BY column_name ORDER BY column_name)
LAG(column_name, [offset], [default_value]) OVER (PARTITION BY column_name ORDER BY column_name)
column_name— la columna de la que queremos sacar los datos.offset(opcional) — el desplazamiento respecto a la fila actual. Por defecto es 1.default_value(opcional) — el valor que se devuelve si no existe la fila con el desplazamiento requerido (por ejemplo, cuando estás en la última fila).OVER()— aquí defines la "ventana" sobre la que se hace el cálculo. Normalmente esORDER BY, a veces se usaPARTITION BYpara separar los datos en grupos.
Ejemplo: Simplemente LEAD() y LAG()
Vamos a crear una tabla sencilla events para nuestros experimentos:
CREATE TABLE events (
id SERIAL PRIMARY KEY,
event_name TEXT NOT NULL,
event_date TIMESTAMP NOT NULL
);
INSERT INTO events (event_name, event_date)
VALUES
('Evento A', '2023-10-01 10:00:00'),
('Evento B', '2023-10-01 11:00:00'),
('Evento C', '2023-10-01 12:00:00'),
('Evento D', '2023-10-01 13:00:00');
Ahora queremos ver cuándo ocurrieron los eventos anteriores y siguientes respecto a cada evento:
SELECT
id,
event_name,
event_date,
LAG(event_date) OVER (ORDER BY event_date) AS evento_anterior,
LEAD(event_date) OVER (ORDER BY event_date) AS evento_siguiente
FROM events;
El resultado será así:
| id | event_name | event_date | evento_anterior | evento_siguiente |
|---|---|---|---|---|
| 1 | Evento A | 2023-10-01 10:00:00 | NULL | 2023-10-01 11:00:00 |
| 2 | Evento B | 2023-10-01 11:00:00 | 2023-10-01 10:00:00 | 2023-10-01 12:00:00 |
| 3 | Evento C | 2023-10-01 12:00:00 | 2023-10-01 11:00:00 | 2023-10-01 13:00:00 |
| 4 | Evento D | 2023-10-01 13:00:00 | 2023-10-01 12:00:00 | NULL |
Aquí LAG() saca los datos de la fila anterior y LEAD() de la siguiente. El primer evento no tiene a quién mirar atrás, y el último no tiene a quién adelantar, así que reciben NULL.
Ejemplo: diferencia entre eventos
A veces necesitamos saber cuánto tiempo ha pasado entre eventos. Para eso, simplemente restamos un tiempo de otro:
SELECT
id,
event_name,
event_date,
event_date - LAG(event_date) OVER (ORDER BY event_date) AS tiempo_desde_evento_anterior
FROM events;
Resultado:
| id | event_name | event_date | tiempo_desde_evento_anterior |
|---|---|---|---|
| 1 | Evento A | 2023-10-01 10:00:00 | NULL |
| 2 | Evento B | 2023-10-01 11:00:00 | 01:00:00 |
| 3 | Evento C | 2023-10-01 12:00:00 | 01:00:00 |
| 4 | Evento D | 2023-10-01 13:00:00 | 01:00:00 |
Ejemplo: usando PARTITION BY
Supón que tenemos varios usuarios, cada uno con sus propios eventos. Queremos encontrar la diferencia entre eventos para cada usuario.
Actualizamos la tabla y añadimos la columna user_id:
ALTER TABLE events ADD COLUMN user_id INT;
UPDATE events SET user_id = 1 WHERE id <= 2;
UPDATE events SET user_id = 2 WHERE id > 2;
Ahora tenemos dos usuarios. Usamos PARTITION BY para calcular dentro de cada grupo:
SELECT
user_id,
event_name,
event_date,
event_date - LAG(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS tiempo_desde_evento_anterior
FROM events;
Resultado:
| user_id | event_name | event_date | tiempo_desde_evento_anterior |
|---|---|---|---|
| 1 | Evento A | 2023-10-01 10:00:00 | NULL |
| 1 | Evento B | 2023-10-01 11:00:00 | 01:00:00 |
| 2 | Evento C | 2023-10-01 12:00:00 | NULL |
| 2 | Evento D | 2023-10-01 13:00:00 | 01:00:00 |
Ejemplos de uso en tareas reales
- Logs de eventos: analizar el tiempo entre eventos, como login y logout de usuario.
- Time-tracking: calcular el tiempo dedicado a tareas concretas.
- Analítica de comportamiento: analizar la secuencia de acciones de clientes en una tienda online.
- Cálculo de métricas acumulativas: usar funciones de ventana para trabajar con series temporales.
Errores típicos
Al trabajar con LEAD() y LAG() los problemas clave pueden ser:
- Olvidar
ORDER BYenOVER(). Sin eso la función no puede saber el orden de las filas. - Problemas con intervalos de tiempo o tipos de datos (
TIMESTAMPvsDATE). - Ignorar los valores
NULLque pueden aparecer al principio y al final de la ventana.
Para evitar estos errores, revisa siempre tus datos y asegúrate de definir bien la ventana para las operaciones.
GO TO FULL VERSION