una números numero lista huecos faltantes faltante encontrar consecutivos sql oracle plsql gaps-and-islands

sql - numero - ¿Cómo verificar cualquier número faltante de una serie de números?



faltantes en una lista de números consecutivos excel (9)

Aquí hay una solución que:

  • Se basa en la función LAG de Oracle
  • No requiere conocimiento de la secuencia completa (pero, por lo tanto, no detecta si se omitieron los primeros o últimos números en secuencia)
  • Enumera los valores que rodean las listas de números que faltan
  • Enumera las listas de números que faltan como grupos contiguos (quizás convenientes para informar)
  • Trágicamente falla para listas muy grandes de números faltantes, debido a las limitaciones de listagg

SQL:

WITH MentionedValues /*this would just be your actual table, only defined here to provide data for this example */ AS (SELECT * FROM ( SELECT LEVEL + 7000 seqnum FROM DUAL CONNECT BY LEVEL <= 10000) WHERE seqnum NOT IN (7003,7007,7008,7009)--omit those four per example ), Ranges /*identifies all ranges between adjacent rows*/ AS (SELECT seqnum AS seqnum_curr, LAG (seqnum, 1) OVER (ORDER BY seqnum) AS seqnum_prev, seqnum - (LAG (seqnum, 1) OVER (ORDER BY seqnum)) AS diff FROM MentionedValues) SELECT Ranges.*, ( SELECT LISTAGG (Ranges.seqnum_prev + LEVEL, '','') WITHIN GROUP (ORDER BY 1) FROM DUAL CONNECT BY LEVEL < Ranges.diff) "MissingValues" /*count from lower seqnum+1 up to lower_seqnum+(diff-1)*/ FROM Ranges WHERE diff != 1 /*ignore when diff=1 because that means the numers are sequential without skipping any*/ ;

Salida:

SEQNUM_CURR SEQNUM_PREV DIFF MissingValues 7004 7002 2 "7003" 7010 7006 4 "7007,7008,7009"

Estoy haciendo un proyecto creando un sistema de admisión para una universidad; Las tecnologías son Java y Oracle.

En una de las tablas, se almacenan los números de serie pre-generados. Más tarde, contra esos números de serie, se ingresarán los datos del formulario del solicitante. Mi requisito es que cuando se complete el proceso de entrada, tendré que generar un informe de Lotes. Si durante la alimentación de números de serie pre-generados algún número de secuencia desapareció.

Por ejemplo, digamos en una tabla, los números de secuencia son 7001, 7002, 7004, 7005, 7006, 7010. De la serie anterior está claro que de 7001 a 7010 los números que faltan son 7003, 7007, 7008 y 7009

¿Existe alguna función DBMS disponible en Oracle para averiguar estos números o si algún procedimiento almacenado puede cumplir mi propósito, por favor sugiera un algoritmo?

Puedo encontrar algunas técnicas en Java, pero por velocidad quiero encontrar la solución en Oracle.


Esto funcionó pero selecciona la primera secuencia (valor de inicio) ya que no tiene predecesor. Probado en SQL Server pero debería funcionar en Oracle

SELECT s.sequence FROM seqs s WHERE s.sequence - (SELECT sequence FROM seqs WHERE sequence = s.sequence-1) IS NULL

Aquí hay un resultado de prueba

Table ------------- 7000 7001 7004 7005 7007 7008 Result ---------- 7000 7004 7007

Para obtener una secuencia no asignada, simplemente haga el value[i] - 1 donde i es mayor en la primera fila, por ejemplo (7004 - 1 = 7003 and 7007 - 1 = 7006) que son secuencias disponibles

Creo que puedes mejorar en esta simple consulta.


Esto funciona en postgres> = 8.4. Con algunas modificaciones leves en la sintaxis de CTE, también podría funcionar para Oracle y Microsoft.

-- EXPLAIN ANALYZE WITH missing AS ( WITH RECURSIVE fullhouse AS ( SELECT MIN(num)+1 as num FROM numbers n0 UNION ALL SELECT 1+ fh0.num AS num FROM fullhouse fh0 WHERE EXISTS ( SELECT * FROM numbers ex WHERE ex.num > fh0.num ) ) SELECT * FROM fullhouse fh1 EXCEPT ( SELECT num FROM numbers nx) ) SELECT * FROM missing;


Habría sugerido connect by level como lo ha hecho Stefan , sin embargo, no puede usar una consulta secundaria en esta declaración, lo que significa que no es realmente adecuado para usted, ya que necesita saber cuáles son los valores máximo y mínimo de tu secuencia son

Yo sugeriría que una función de tabla alineada podría ser la mejor manera de generar los números que necesita para hacer la unión. Para que esto funcione, necesitaría un objeto en su base de datos para devolver los valores a:

create or replace type t_num_array as table of number;

Entonces la función:

create or replace function generate_serial_nos return t_num_array pipelined is l_first number; l_last number; begin select min(serial_no), max_serial_no) into l_first, l_last from my_table ; for i in l_first .. l_last loop pipe row(i); end loop; return; end generate_serial_nos; /

Usando esta función, lo siguiente devolvería una lista de números de serie, entre el mínimo y el máximo.

select * from table(generate_serial_nos);

Lo que significa que su consulta para averiguar qué números de serie faltan se convierte en:

select serial_no from ( select * from table(generate_serial_nos) ) generator left outer join my_table actual on generator.column_value = actual.serial_no where actual.serial_no is null


Prueba esto:

SELECT t1.SequenceNumber + 1 AS "From", MIN(t2.SequenceNumber) - 1 AS "To" FROM MyTable t1 JOIN MyTable t2 ON t1.SequenceNumber < t2.SequenceNumber GROUP BY t1.SequenceNumber HAVING t1.SequenceNumber + 1 < MIN(t2.SequenceNumber)

Aquí está el resultado para la secuencia 7001, 7002, 7004, 7005, 7006, 7010:

From To 7003 7003 7007 7009


Una forma sencilla de obtener su respuesta para su escenario es esta:

create table test1 ( a number(9,0)); insert into test1 values (7001); insert into test1 values (7002); insert into test1 values (7004); insert into test1 values (7005); insert into test1 values (7006); insert into test1 values (7010); commit; select n.n from (select ROWNUM + 7001 as n from dual connect by level <= 9) n left join test1 t on n.n = t.a where t.a is null;

La selección le dará la respuesta de su ejemplo. Esto solo tiene sentido, si sabe de antemano en qué rango están sus números y el rango no debería ser demasiado grande. El primer número debe ser el desplazamiento en la parte ROWNUM y la longitud de la secuencia es el límite al nivel en la connect by parte.


Una solución sin codificar el 9:

select min_a - 1 + level from ( select min(a) min_a , max(a) max_a from test1 ) connect by level <= max_a - min_a + 1 minus select a from test1

Resultados:

MIN_A-1+LEVEL ------------- 7003 7007 7008 7009 4 rows selected.


SELECT ROWNUM "Missing_Numbers" FROM dual CONNECT BY LEVEL <= (SELECT MAX(a) FROM test1) MINUS SELECT a FROM test1 ;


select A.ID + 1 As ID From [Missing] As A Where A.ID + 1 Not IN (Select ID from [Missing]) And A.ID < n Data: ID 1 2 5 7 Result: ID 3 4 6