Tengo alrededor de mil millones de filas de datos en una tabla con un nombre y un número entero en el rango 1-288. Para un nombre dado , cada int es único, y no todos los enteros posibles en el rango están presentes, por lo que hay huecos.
Esta consulta genera un caso de ejemplo:
--what I have:
SELECT *
FROM ( VALUES ('foo', 2),
('foo', 3),
('foo', 4),
('foo', 10),
('foo', 11),
('foo', 13),
('bar', 1),
('bar', 2),
('bar', 3)
) AS baz ("name", "int")
Me gustaría generar una tabla de búsqueda con una fila para cada nombre y secuencia de enteros contiguos. Cada una de esas filas contendría:
nombre - el valor del comienzo de la columna de nombre - el primer entero en el final de la secuencia contigua - el valor final en el intervalo de la secuencia contigua - final - inicio + 1
Esta consulta genera resultados de ejemplo para el ejemplo anterior:
--what I need:
SELECT *
FROM ( VALUES ('foo', 2, 4, 3),
('foo', 10, 11, 2),
('foo', 13, 13, 1),
('bar', 1, 3, 3)
) AS contiguous_ranges ("name", "start", "end", span)
Debido a que tengo tantas filas, más eficiente es mejor. Dicho esto, solo tengo que ejecutar esta consulta una vez, por lo que no es un requisito absoluto.
¡Gracias por adelantado!
Editar:
Debo agregar que las soluciones PL / pgSQL son bienvenidas (explique cualquier truco de fantasía: todavía soy nuevo en PL / pgSQL).
fuente
Respuestas:
¿Qué hay de usar
with recursive
vista de prueba:
consulta:
resultado:
Me interesaría saber cómo funciona eso en su tabla de mil millones de filas.
fuente
Puede hacerlo con las funciones de ventanas. La idea básica es utilizar
lead
ylag
de ventanas funciones para tirar filas por delante y por detrás de la fila actual. Entonces podemos calcular si tenemos el inicio o el final de la secuencia:(Utilicé una vista para que la lógica sea más fácil de seguir a continuación). Ahora sabemos si la fila es un principio o un final. Tenemos que colapsar eso en fila:
Me parece correcto :)
fuente
Otra solución de función de ventana. No tengo idea de la eficiencia, he agregado el plan de ejecución al final (aunque con tan pocas filas, probablemente no tenga mucho valor). Si quieres jugar: prueba de SQL-Fiddle
Tabla y datos:
Consulta:
Plan de consulta
fuente
En SQL Server, agregaría una columna más llamada previousInt:
Usaría una restricción CHECK para asegurarme de que previousInt <int, y una restricción FK (name, previousInt) se refieren a (name, int), y un par de restricciones más para garantizar la integridad de los datos. Hecho esto, seleccionar huecos es trivial:
Para acelerarlo, podría crear un índice filtrado que incluiría solo huecos. Esto significa que todas sus brechas se calculan previamente, por lo que las selecciones son muy rápidas y las restricciones aseguran la integridad de sus datos calculados previamente. Estoy usando mucho tales soluciones, están en todo mi sistema.
fuente
Puedes buscar el Método Tabibitosan:
Básicamente:
Creo que esta actuación mejor:
fuente
un plan aproximado:
Repita desde 2. hasta que no ocurra más actualización. A partir de ahí, se complica, Gordian, con una agrupación de máx. De minutos y mín. De máx. Supongo que elegiría un lenguaje de programación.
PD: Una buena tabla de muestra con algunos valores de muestra estaría bien, lo que podría ser utilizado por todos, por lo que no todos crean sus datos de prueba desde cero.
fuente
Esta solución está inspirada en nate c la respuesta usando las funciones de ventanas y la cláusula OVER. Curiosamente, esa respuesta vuelve a las subconsultas con referencias externas. Es posible completar la consolidación de filas utilizando otro nivel de funciones de ventanas. Puede que no parezca demasiado bonito, pero supongo que es más eficiente ya que utiliza la lógica incorporada de las potentes funciones de ventanas.
Me di cuenta de la solución de Nate que el conjunto inicial de filas ya prodigaba los indicadores necesarios para 1) seleccionar los valores de rango inicial y final Y 2) para eliminar las filas adicionales en el medio. La consulta tiene subconsultas anidadas dos profundas solo debido a las limitaciones de las funciones de ventanas, que restringen cómo se pueden usar los alias de columna. Lógicamente, podría haber producido los resultados con solo una subconsulta anidada.
Algunas otras notas : El siguiente es el código para SQLite3. El dialecto SQLite se deriva de postgresql, por lo que es muy similar e incluso podría funcionar sin modificaciones. Agregué restricciones de encuadre a las cláusulas OVER, ya que las funciones
lag()
ylead()
solo necesitan una ventana de una sola fila, antes y después respectivamente (por lo que no era necesario mantener el conjunto predeterminado de todas las filas anteriores). También opté por los nombresfirst
ylast
dado que la palabraend
está reservada.Los resultados son como las otras respuestas, como se espera:
fuente