Tengo una tabla con números como este (el estado es GRATUITO o ASIGNADO)
id_set number status ----------------------- 1 000001 ASIGNADO 1 000002 GRATIS 1 000003 ASIGNADO 1 000004 GRATIS 1 000005 GRATIS 1 000006 ASIGNADO 1 000007 ASIGNADO 1 000008 GRATIS 1 000009 GRATIS 1 000010 GRATIS 1 000011 ASIGNADO 1 000012 ASIGNADO 1 000013 ASIGNADO 1 000014 GRATIS 1 000015 ASIGNADO
y necesito encontrar "n" números consecutivos, por lo que para n = 3, la consulta devolvería
1 000008 GRATIS 1 000009 GRATIS 1 000010 GRATIS
Debería devolver solo el primer grupo posible de cada id_set (de hecho, se ejecutaría solo para id_set por consulta)
Estaba comprobando las funciones de WINDOW, intenté algunas consultas como COUNT(id_number) OVER (PARTITION BY id_set ROWS UNBOUNDED PRECEDING)
, pero eso es todo lo que obtuve :) No podía pensar en la lógica, cómo hacer eso en Postgres.
Estaba pensando en crear una columna virtual usando las funciones de VENTANA contando las filas anteriores para cada número donde status = 'FREE', luego seleccione el primer número, donde count es igual a mi número "n".
O quizás agrupe los números por estado, pero solo de un ASIGNADO a otro ASIGNADO y seleccione solo grupos que contengan al menos "n" números
EDITAR
Encontré esta consulta (y la cambié un poco)
WITH q AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY id_set, status ORDER BY number) AS rnd,
ROW_NUMBER() OVER (PARTITION BY id_set ORDER BY number) AS rn
FROM numbers
)
SELECT id_set,
MIN(number) AS first_number,
MAX(number) AS last_number,
status,
COUNT(number) AS numbers_count
FROM q
GROUP BY id_set,
rnd - rn,
status
ORDER BY
first_number
que produce grupos de números GRATUITOS / ASIGNADOS, pero me gustaría tener todos los números del primer grupo que cumpla la condición
id_set
o solo uno? Actualice su pregunta si esto se entiende como parte del principio. (Para que otros puedan ver los requisitos completos y ofrecer sus sugerencias o actualizar sus respuestas.)Una variante simple y rápida :
Requiere una secuencia de números sin espacios
number
(como se proporciona en la pregunta).Funciona para cualquier número de valores posibles
status
además'FREE'
, incluso conNULL
.La principal característica es restar
row_number()
denumber
después de la eliminación de filas que no confieren. Los números consecutivos terminan en el mismogrp
, ygrp
también se garantiza que están en orden ascendente .Entonces puedes
GROUP BY grp
y contar los miembros. Ya que parece querer la primera aparición,ORDER BY grp LIMIT 1
y obtiene la posición inicial y la longitud de la secuencia (puede ser> = n ).Conjunto de filas
Para obtener un conjunto real de números, no busque la tabla otra vez. Mucho más barato con
generate_series()
:Si realmente desea una cadena con ceros a la izquierda como se muestra en sus valores de ejemplo, use
to_char()
con elFM
modificador (modo de relleno):SQL Fiddle con caso de prueba extendido y ambas consultas.
Respuesta estrechamente relacionada:
fuente
Esta es una forma bastante genérica de hacer esto.
Tenga en cuenta que depende de que su
number
columna sea consecutiva. Si no es una función de Windows y / o una solución de tipo CTE, probablemente será necesaria:fuente
M.number-consec+1
(por ejemplo, para 10 debería serlo10-3+1=8
).number
campo. Buena decisión en matemáticas, lo corregiré.EXISTS
podría simplificarse. Como solo necesitamos asegurarnos de que existan n filas anteriores, podemos descartar elAND status = 'FREE'
. Y me gustaría cambiar la condición en el segundoEXISTS
astatus <> 'FREE'
endurecer contra opciones añadidas en el futuro.Esto devolverá solo el primero de los 3 números. No requiere que los valores de
number
sean consecutivos. Probado en SQL-Fiddle :Y esto mostrará todos los números (donde hay 3 o más
'FREE'
posiciones consecutivas ):fuente
En este caso, 5 números consecutivos, por lo tanto, la diferencia debe ser 4 o, en otras palabras,
count(r3.number) = n
yr2.number = r1.number + n - 1
.Con une:
fuente
JOIN
sintaxis moderna ?fuente
{ }
botón en el editor. ¡Disfrutar!