Detectar días consecutivos del calendario
Use la aritmética de fechas y los números de fila para encontrar rachas de días ininterrumpidos
Detectar días consecutivos del calendario es una lección gratuita de SQL Interview Prep en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de SQL Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de SQL Interview Prep incluye 4 lecciones en total.
El planteamiento de la entrevista
A los entrevistadores les encantan las preguntas sobre rachas porque revelan si realmente comprende las funciones de ventana y la aritmética de fechas. Un enunciado habitual sería: "Dada una tabla con las fechas de inicio de sesión de los usuarios, encuentre cada secuencia ininterrumpida de días naturales consecutivos."
El primer impulso suele ser hacer una autocombinación que compare cada fila con la siguiente, pero esto se vuelve muy costoso en tablas grandes y resulta difícil de expresar. La respuesta profesional utiliza la técnica de brechas e islas. En esta lección aprenderá a detectar días consecutivos de forma clara mediante números de fila y resta de fechas.
Los datos de ejemplo
A lo largo de esta lección utilizaremos una tabla logins con una fila por usuario y por cada día en que estuvo activo. Se supone que los duplicados ya se han eliminado (un inicio de sesión por día natural).
user_id— quién inició sesiónlogin_date— un valor DATE
Para el usuario 1, las fechas son 1, 2 y 3 de enero; después hay una brecha, y luego el 6 y el 7 de enero. Esperamos dos secuencias: una de 3 días y otra de 2 días.
SELECT * FROM logins ORDER BY user_id, login_date;
-- user_id | login_date
-- 1 | 2024-01-01
-- 1 | 2024-01-02
-- 1 | 2024-01-03
-- 1 | 2024-01-06
-- 1 | 2024-01-07La idea central
Este es el truco que permite resolver cualquier problema de días consecutivos. Si ordena las filas por fecha y asigna a cada una un número de fila secuencial, en cualquier secuencia de días consecutivos la diferencia entre la fecha y el número de fila permanece constante.
¿Por qué? Tanto la fecha como el número de fila aumentan exactamente en 1 cada día consecutivo, por lo que su diferencia no cambia. Cuando aparece una brecha, la fecha avanza, pero el número de fila no; así se rompe la constante y comienza un grupo nuevo.
Observar la diferencia
Veámoslo paso a paso para el usuario 1. ROW_NUMBER cuenta 1, 2, 3, 4 y 5. Reste el número de fila (en días) a la fecha y observe el resultado.
- 1 de enero − 1 = 31 de diciembre
- 2 de enero − 2 = 31 de diciembre
- 3 de enero − 3 = 31 de diciembre
- 6 de enero − 4 = 2 de enero
- 7 de enero − 5 = 2 de enero
Los tres primeros comparten el 31 de diciembre; los dos últimos comparten el 2 de enero. Ese valor de referencia compartido es nuestra clave de grupo.
Añadir ROW_NUMBER
El primer paso concreto consiste en asignar un número de fila, con una partición por usuario para que las rachas nunca crucen los límites entre usuarios, y ordenar por fecha.
PARTITION BY user_id reinicia el contador para cada usuario; ORDER BY login_date garantiza que la secuencia siga el calendario.
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY login_date
) AS rn
FROM logins;Calcular la referencia del grupo
Ahora reste rn días a login_date. En PostgreSQL puede restar directamente a una fecha un número entero de días. El resultado es la referencia constante que identifica cada isla.
Observe que no puede hacer referencia al alias rn en el mismo SELECT en el que lo define; por eso primero debe envolver la consulta anterior en un CTE o una subconsulta.
WITH numbered AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
)
SELECT
user_id,
login_date,
login_date - rn AS grp
FROM numbered;Agrupar las islas
Con la referencia calculada, cada secuencia consecutiva comparte el mismo valor de grp. Agrupe por user_id y grp, y después utilice funciones de agregación para obtener el inicio, el final y la duración de cada secuencia.
MIN(login_date)— primer día de la rachaMAX(login_date)— último día de la rachaCOUNT(*)— número de días de la racha
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
)
SELECT
user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
ORDER BY user_id, streak_start;Diferencias entre dialectos
La sintaxis de la aritmética de fechas varía. Menciónelo en las entrevistas para demostrar amplitud de conocimientos.
- PostgreSQL:
login_date - rn(fecha menos días enteros) - MySQL:
DATE_SUB(login_date, INTERVAL rn DAY) - SQL Server:
DATEADD(day, -rn, login_date)
La lógica es idéntica; solo cambian los nombres de las funciones. El modelo mental portable es "desplazar cada fecha hacia atrás según su posición para que una secuencia continua se reduzca a una única constante".
-- SQL Server version of the anchor
DATEADD(day, -1 * rn, login_date) AS grp¿Por qué no utilizar una autocombinación?
Un entrevistador podría preguntarle por qué evitó una autocombinación como l1.login_date = l2.login_date + 1. Puede mencionar estos motivos:
- Una autocombinación solo comprueba la adyacencia, no la secuencia completa; para construir rachas completas todavía hace falta agrupar.
- Puede multiplicar las filas y tiene un coste O(n²) si no hay buenos índices.
- El método de los números de fila realiza una sola pasada ordenada y es mucho más escalable.
Las funciones de ventana son la respuesta moderna y esperada para estos problemas.
Protegerse contra los duplicados
Toda la técnica supone que hay una fila por usuario y por día. Si la fuente contiene varios inicios de sesión en un mismo día, dos filas con la misma fecha reciben números de fila distintos, lo que corrompe la referencia.
Para evitarlo, deduplique primero: convierta las marcas de tiempo a fechas y utilice DISTINCT, o use DENSE_RANK sobre la fecha en lugar de ROW_NUMBER para que las fechas iguales compartan el mismo número.
WITH days AS (
SELECT DISTINCT user_id, login_ts::date AS login_date
FROM raw_logins
)
SELECT * FROM days;La solución completa
Al reunir todas las piezas se obtiene una respuesta clara y lista para una entrevista, que enumera cada secuencia de días consecutivos con su inicio, final y duración.
Esta misma estructura —deduplicar, numerar, restar y agrupar— resuelve prácticamente cualquier pregunta sobre elementos "consecutivos" que le planteen.
WITH days AS (
SELECT DISTINCT user_id, login_ts::date AS login_date
FROM raw_logins
),
numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM days
)
SELECT user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
ORDER BY user_id, streak_start;Comprobación rápida
Compruebe si ha entendido el truco central.
Resumen
Ha aprendido el patrón fundamental para días consecutivos:
- Deduplicar hasta dejar una fila por usuario y por día.
- ROW_NUMBER ordenado por fecha y con una partición por usuario.
- Restar el número de fila a la fecha para obtener una referencia constante por secuencia.
- GROUP BY de la referencia y uso de funciones de agregación para obtener el inicio, el final y la duración.
Esta estructura de brechas e islas escala en una sola pasada y supera a las autocombinaciones. A continuación la utilizará para calcular la racha más larga de cada usuario.
Preguntas frecuentes
¿La lección «Detectar días consecutivos del calendario» es gratis?
Sí — el texto completo de «Detectar días consecutivos del calendario» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de SQL Interview Prep, actualiza a CoddyKit PRO. El curso de SQL Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «Detectar días consecutivos del calendario»?
Use la aritmética de fechas y los números de fila para encontrar rachas de días ininterrumpidos Practicas SQL Interview Prep con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar SQL Interview Prep?
No se requiere experiencia previa. SQL Interview Prep en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Detectar días consecutivos del calendario»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de SQL Interview Prep?
Sí. Cada lección de SQL Interview Prep incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Detectar días consecutivos del calendario
- Racha más larga por usuario
- N filas consecutivas que cumplen una condición
- Racha activa actual hasta hoy