El truco de la diferencia de números de fila
Reste ROW_NUMBER de una secuencia para agrupar valores consecutivos en segmentos
El truco de la diferencia de números de fila es una lección gratuita de Coding Interview Prep en CoddyKit. Esta es la lección 2 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 Coding Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Coding Interview Prep incluye 4 lecciones en total.
La clave de isla más elegante
La técnica de la diferencia de números de fila es la que más quieren ver los entrevistadores para islas de enteros o fechas consecutivos. Produce la clave de grupo con una sola resta, sin LAG ni suma acumulada.
La idea completa es restar un ROW_NUMBER al propio valor. En cualquier secuencia de valores consecutivos, tanto el valor como el número de fila aumentan exactamente en 1 en cada paso, por lo que su diferencia es constante en toda la secuencia. Esa constante es la clave de su isla.
Por qué la diferencia permanece constante
Considere dos filas adyacentes de una secuencia consecutiva. Al pasar de una a la siguiente, el valor aumenta en 1 y el número de fila aumenta en 1. Al restarlos, los +1 se cancelan, de modo que value - row_number no cambia.
Pero en cuanto aparece un hueco, el valor aumenta en más de 1 mientras que el número de fila solo aumenta en 1. La diferencia cambia a una nueva constante. Ese cambio es exactamente lo que separa una isla de la siguiente.
Así se ve en nuestros datos
Recuerde los días de inicio de sesión 1, 2, 3, 7, 8, 10. Coloquemos el número de fila y la diferencia uno al lado de la otra:
- day 1, rn 1, diff 0
- day 2, rn 2, diff 0
- day 3, rn 3, diff 0
- day 7, rn 4, diff 3
- day 8, rn 5, diff 3
- day 10, rn 6, diff 4
Las diferencias (0,0,0,3,3,4) dividen perfectamente las filas en las tres islas. La misma diferencia significa la misma isla.
SELECT
day_no,
ROW_NUMBER() OVER (ORDER BY day_no) AS rn,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM logins
ORDER BY day_no;Agrupar en islas
Con la diferencia como clave de grupo, la consulta final es la agrupación estándar. Envolvemos la diferencia en un CTE y aplicamos GROUP BY:
Esto devuelve las mismas tres islas que antes, pero el SQL es más breve y claro que la versión con LAG y suma acumulada. Para secuencias de enteros o con pasos uniformes, esta es la primera opción que debe considerar.
WITH keyed AS (
SELECT
day_no,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM logins
)
SELECT
MIN(day_no) AS start_day,
MAX(day_no) AS end_day,
COUNT(*) AS length
FROM keyed
GROUP BY grp
ORDER BY start_day;La trampa: los valores deben avanzar de uno en uno
El truco simple de la diferencia supone que la secuencia aumenta exactamente en 1 en cada paso. Esto se cumple con enteros sin huecos y días consecutivos del calendario, pero deja de funcionar si los valores avanzan con otro intervalo fijo o si hay duplicados.
- Incluso los valores pares 2,4,6,8 parecerán huecos al restar el número de fila al valor.
- Los valores duplicados desajustan la alineación, porque el número de fila sigue aumentando mientras el valor no cambia.
Comprender esta limitación y saber cómo corregirla es lo que distingue un truco memorizado de una comprensión real.
Corregir secuencias con paso fijo
Si los valores avanzan con una constante conocida k en lugar de 1, normalícelos primero: divida el valor entre k (o use value / k para enteros) para que cada paso vuelva a ser 1 y, después, reste el número de fila.
Por ejemplo, para números pares que avanzan de 2 en 2, use day_no / 2 - ROW_NUMBER(). Ahora el valor normalizado aumenta en 1 por cada elemento consecutivo, lo que restablece la propiedad de diferencia constante.
SELECT
val,
(val / 2) - ROW_NUMBER() OVER (ORDER BY val) AS grp
FROM even_series
ORDER BY val;Aplicarlo a fechas
Las fechas son el caso real más común. Las fechas del calendario no se pueden restar directamente de un número de fila, así que primero debe convertirlas en un recuento de días. En Postgres, reste una fecha ancla fija para obtener un número entero de días y aplique después el mismo truco.
Como las fechas consecutivas del calendario difieren en 1, la diferencia entre el recuento de días y el número de fila vuelve a ser constante dentro de una isla.
WITH keyed AS (
SELECT
login_date,
(login_date - DATE '2000-01-01')
- ROW_NUMBER() OVER (ORDER BY login_date) AS grp
FROM daily_logins
)
SELECT MIN(login_date) AS start_date,
MAX(login_date) AS end_date,
COUNT(*) AS days_in_run
FROM keyed GROUP BY grp ORDER BY start_date;Diferencias de fechas entre dialectos
El paso de fecha a entero varía según el motor, y los entrevistadores valoran que conozca las diferencias entre dialectos:
- Postgres: reste un literal de fecha:
login_date - DATE '2000-01-01'devuelve un entero. - MySQL: use
DATEDIFF(login_date, '2000-01-01'). - SQL Server: use
DATEDIFF(day, '2000-01-01', login_date).
En algunos motores hay una alternativa aún más elegante: reste directamente ROW_NUMBER días a la fecha mediante aritmética de intervalos y, después, agrupe con GROUP BY usando como clave la fecha ancla resultante.
SELECT
login_date,
login_date - (ROW_NUMBER() OVER (ORDER BY login_date)
* INTERVAL '1 day') AS grp_date
FROM daily_logins;Añadir particiones por grupo
Para obtener islas por usuario, particione el número de fila por la columna del grupo. Es fundamental que la clave del grupo incluya también la columna de partición, porque dos usuarios distintos pueden producir casualmente el mismo valor de diferencia.
Por tanto, use GROUP BY tanto con user_id como con la diferencia calculada. Olvidar user_id en el GROUP BY final es un error sutil que a los entrevistadores les encanta detectar.
WITH keyed AS (
SELECT user_id, day_no,
day_no - ROW_NUMBER()
OVER (PARTITION BY user_id ORDER BY day_no) AS grp
FROM logins
)
SELECT user_id, MIN(day_no) AS start_day,
MAX(day_no) AS end_day, COUNT(*) AS len
FROM keyed
GROUP BY user_id, grp
ORDER BY user_id, start_day;Truco frente a LAG: cuál usar
Ahora tiene dos técnicas sólidas en su conjunto de herramientas. Elija de forma deliberada:
- Diferencia de números de fila: es la opción más breve y clara para secuencias de valores con pasos uniformes (enteros sin huecos, fechas consecutivas). Es la primera opción cuando la adyacencia significa «difiere en una constante».
- LAG más suma acumulada: es más flexible cuando la adyacencia no corresponde a un paso numérico fijo, por ejemplo, «tiene el mismo estado que la fila anterior» o sigue reglas personalizadas irregulares.
En la entrevista, explique qué opción eligió y por qué; el razonamiento impresiona más que la sintaxis.
Tratar los duplicados de forma preventiva
Si un valor puede repetirse y aun así quiere una isla por cada secuencia consecutiva, elimine primero los duplicados con DISTINCT o mediante una agrupación, de modo que el número de fila se alinee uno a uno con los valores. Como alternativa, use DENSE_RANK en lugar de ROW_NUMBER para que los valores empatados compartan rango.
Pregunte siempre al entrevistador si puede haber duplicados; la estrategia adecuada depende de si los duplicados deben prolongar la secuencia o ignorarse dentro de ella.
WITH d AS (SELECT DISTINCT day_no FROM logins)
SELECT day_no,
day_no - ROW_NUMBER() OVER (ORDER BY day_no) AS grp
FROM d;Comprobación rápida
Asegúrese de comprender por qué funciona el truco.
Repaso: el truco de la diferencia
Ahora cuenta con la clave de isla más sencilla:
- Fórmula de la clave:
value - ROW_NUMBER() OVER (ORDER BY value)es constante en cada secuencia consecutiva. - Agrupe con
GROUP BYusando la diferencia para obtener el inicio, el final y la longitud. - Para secuencias con paso fijo, normalice primero (divida por el paso).
- Para fechas, conviértalas en un recuento entero de días mediante la función de diferencia del dialecto.
- Por grupo: use
PARTITION BYpara el número de fila e incluya la columna del grupo en elGROUP BYfinal. - Proteja el resultado frente a duplicados con
DISTINCToDENSE_RANK.
A continuación, cambiaremos el foco de las islas a los espacios vacíos: encontrar huecos.
Preguntas frecuentes
¿La lección «El truco de la diferencia de números de fila» es gratis?
Sí — el texto completo de «El truco de la diferencia de números de fila» 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 Coding Interview Prep, actualiza a CoddyKit PRO. El curso de Coding Interview Prep incluye 4 lecciones en total.
¿Qué aprenderé en «El truco de la diferencia de números de fila»?
Reste ROW_NUMBER de una secuencia para agrupar valores consecutivos en segmentos Practicas Coding 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 Coding Interview Prep?
No se requiere experiencia previa. Coding 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 2 de 4.
¿Cuánto tiempo toma la lección «El truco de la diferencia de números de fila»?
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 Coding Interview Prep?
Sí. Cada lección de Coding 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
- Reconocer un problema de huecos y segmentos
- El truco de la diferencia de números de fila
- Encontrar huecos en una secuencia
- Segmentos con cambios de fecha y estado