Tenemos una base de datos con una tabla cuyos valores fueron importados de otro sistema. Hay una columna de incremento automático y no hay valores duplicados, pero faltan valores. Por ejemplo, ejecutando esta consulta:
select count(id) from arrc_vouchers where id between 1 and 100
debería devolver 100, pero devuelve 87 en su lugar. ¿Hay alguna consulta que pueda ejecutar que devuelva los valores de los números faltantes? Por ejemplo, los registros pueden existir para id 1-70 y 83-100, pero no hay registros con id de 71-82. Quiero devolver 71, 72, 73, etc.
es posible?
mysql
sql
gaps-and-islands
EmmyS
fuente
fuente
select l.id + 1 as start from sequence as l left outer join sequence as r on l.id + 1 = r.id where r.id is null;
Respuestas:
Actualizar
ConfexianMJS proporcionó una respuesta mucho mejor en términos de rendimiento.
La respuesta (no tan rápida como sea posible)
Aquí está la versión que funciona en una mesa de cualquier tamaño (no solo en 100 filas):
gap_starts_at
- primera identificación en la brecha actualgap_ends_at
- última identificación en la brecha actualfuente
order number
que estaba buscando espacios en blanco no es distinto (la tabla almacena líneas de pedido, por lo que el número de pedido al que pertenecen se repite para cada línea). Primera consulta: 2812 filas en conjunto (1 min 31,09 seg) . Hizo otra tabla seleccionando distintos números de orden. Su consulta sin mis repeticiones: 1009 filas en conjunto (18.04 segundos)SELECT MIN(id) FROM table
?Esto me funcionó para encontrar los espacios en una tabla con más de 80k filas:
Resultado:
Tenga en cuenta que el orden de las columnas
expected
ygot
es fundamental.Si sabe que
YourCol
no comienza en 1 y eso no importa, puede reemplazarcon
Nuevo resultado:
Si necesita realizar algún tipo de tarea de script de shell en los ID que faltan, también puede usar esta variante para producir directamente una expresión sobre la que pueda iterar en bash.
Esto produce una salida como esta
Luego puede copiarlo y pegarlo en un bucle for en una terminal bash para ejecutar un comando para cada ID
Es lo mismo que el anterior, solo que es legible y ejecutable. Al cambiar el comando "CONCAT" anterior, se puede generar sintaxis para otros lenguajes de programación. O tal vez incluso SQL.
fuente
CONVERT( YourCol, UNSIGNED )
dará mejores resultados si YourCol no es ya un número entero.SELECT MAX(YourCol) FROM YourTable;
SELECT IF((z.got-IF(z.over>0, z.over, 0)-1)>z.expected, CONCAT(z.expected,' thru ',(z.got-IF(z.over>0, z.over, 0)-1)), z.expected) AS missing FROM ( SELECT @rownum:=@rownum+1 AS expected, @target-@missing AS under, (@missing:=@missing+IF(@rownum=YourCol, 0, YourCol-@rownum))-@target AS over, IF(@rownum=YourCol, 0, @rownum:=YourCol) AS got FROM (SELECT @rownum:=0, @missing:=0, @target:=10) AS a JOIN YourTable ORDER BY YourCol ) AS z WHERE z.got!=0 AND z.under>0;
Consulta rápida y sucia que debería hacer el truco:
Esto le dará una tabla que muestra la identificación a la que le faltan identificadores encima, y el next_id que existe, y cuántos faltan entre ...
fuente
Si está usando un
MariaDB
, tiene una opción más rápida (800%) usando el motor de almacenamiento de secuencias :fuente
"SELECT MAX(column) FROM table"
y configurando una variable del resultado, digamos $ MAX ... luego se puede escribir la declaración sql"SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
mi sintaxis está basada en phpSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
con variables MySQL.Cree una tabla temporal con 100 filas y una sola columna que contenga los valores del 1 al 100.
Outer Únase a esta tabla con su tabla arrc_vouchers y seleccione los valores de una sola columna donde la identificación de arrc_vouchers es nula.
Codificando esto a ciegas, pero debería funcionar.
fuente
Una solución alternativa que requiere una consulta + algún código haciendo algún procesamiento sería:
Tenga en cuenta que la consulta no contiene ninguna subselección que sepamos que el planificador de MySQL no la maneja correctamente.
Eso devolverá una entrada por centralValue (cValue) que no tiene un valor más pequeño (lValue) o un valor mayor (rValue), es decir:
Sin entrar en más detalles (los veremos en los siguientes párrafos) este resultado significa que:
Entonces, la idea básica es hacer uniones DERECHA e IZQUIERDA con la misma tabla viendo si tenemos valores adyacentes por valor (es decir, si el valor central es '3', entonces verificamos 3-1 = 2 a la izquierda y 3 + 1 en derecha), y cuando una FILA tiene un valor NULO en DERECHA o IZQUIERDA, sabemos que no hay un valor adyacente.
La salida sin procesar completa de mi tabla es:
Algunas notas:
fuente
Si hay una secuencia que tiene un espacio máximo de uno entre dos números (como 1,3,5,6), la consulta que se puede utilizar es:
source1
id
fuente
basado en la respuesta dada anteriormente por Lucek, este procedimiento almacenado le permite especificar los nombres de tabla y columna que desea probar para encontrar registros no contiguos, respondiendo así la pregunta original y también demostrando cómo se podría usar @var para representar tablas y / o columnas en un procedimiento almacenado.
fuente
Lo probé de diferentes maneras y el mejor rendimiento que encontré fue esta simple consulta:
... one left join para verificar si existe la siguiente identificación , solo si la siguiente si no se encuentra, entonces la subconsulta busca la siguiente identificación que existe para encontrar el final del espacio. Lo hice porque la consulta con igual (=) tiene un mejor rendimiento que el operador mayor que (>).
Usando sqlfiddle , no muestra un rendimiento tan diferente de la consulta de otros, pero en una base de datos real, esta consulta anterior resulta 3 veces más rápida que otras.
El esquema:
Siga a continuación todas las consultas que hice para comparar el rendimiento:
Quizás ayude a alguien y sea útil.
Puede ver y probar mi consulta usando este sqlfiddle :
http://sqlfiddle.com/#!9/6bdca7/1
fuente
Aunque todos parecen funcionar, el conjunto de resultados regresa en un tiempo muy largo cuando hay 50.000 registros.
Usé esto, y encuentra el espacio o el siguiente disponible (último usado + 1) con un retorno mucho más rápido de la consulta.
fuente
Probablemente no sea relevante, pero estaba buscando algo como esto para enumerar los huecos en una secuencia de números y encontré esta publicación, que tiene múltiples soluciones diferentes dependiendo exactamente de lo que está buscando. Estaba buscando el primer espacio disponible en la secuencia (es decir, el siguiente número disponible), y esto parece funcionar bien.
SELECCIONE MIN (l.number_sequence + 1) como nextavabile de pacientes como l LEFT OUTER JOIN pacientes como r en l.number_sequence + 1 = r.number_sequence DONDE r.number_sequence es NULL. ¡Varios otros escenarios y soluciones discutidos allí, desde 2005!
Cómo encontrar valores perdidos en una secuencia con SQL
fuente