Temos um banco de dados com uma tabela cujos valores foram importados de outro sistema. Há uma coluna de incremento automático e não há valores duplicados, mas há valores ausentes. Por exemplo, executando esta consulta:
select count(id) from arrc_vouchers where id between 1 and 100
deve retornar 100, mas retorna 87 em vez disso. Posso executar alguma consulta que retorne os valores dos números ausentes? Por exemplo, os registros podem existir para id 1-70 e 83-100, mas não há registros com ids de 71-82. Eu quero devolver 71, 72, 73, etc.
Isso é possível?
mysql
sql
gaps-and-islands
EmmyS
fonte
fonte
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;
Respostas:
Atualizar
O ConfexianMJS forneceu uma resposta muito melhor em termos de desempenho.
A resposta (não o mais rápido possível)
Esta é a versão que funciona em mesa de qualquer tamanho (não apenas em 100 linhas):
gap_starts_at
- primeiro id na lacuna atualgap_ends_at
- última id na lacuna atualfonte
order number
eu estava procurando por lacunas em não é distinto (a tabela armazena as linhas de pedido, portanto, o número do pedido a que pertencem se repete para cada linha). 1ª consulta: 2812 linhas no conjunto (1 min 31,09 seg) . Fez outra tabela selecionando números de pedido distintos. Sua consulta sem minhas repetições: 1009 linhas no conjunto (18,04 segundos)SELECT MIN(id) FROM table
?Isso funcionou para mim encontrar as lacunas em uma tabela com mais de 80 mil linhas:
Resultado:
Observe que a ordem das colunas
expected
egot
é crítica.Se você sabe que
YourCol
não começa em 1 e que não importa, você pode substituircom
Novo resultado:
Se você precisar realizar algum tipo de tarefa de script de shell nos IDs ausentes, também pode usar essa variante para produzir diretamente uma expressão que possa iterar no bash.
Isso produz uma saída como esta
Você pode então copiar e colar em um loop for em um terminal bash para executar um comando para cada ID
É a mesma coisa que acima, só que é legível e executável. Alterando o comando "CONCAT" acima, a sintaxe pode ser gerada para outras linguagens de programação. Ou talvez até SQL.
fonte
CONVERT( YourCol, UNSIGNED )
dará melhores resultados se YourCol ainda não for um número inteiro.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 e suja que deve resolver o problema:
Isso lhe dará uma tabela mostrando o id que tem ids ausentes acima dele, e next_id que existe, e quantos estão faltando entre ... por exemplo
fonte
Se estiver usando um,
MariaDB
você tem uma opção mais rápida (800%) usando o mecanismo de armazenamento de sequência :fonte
"SELECT MAX(column) FROM table"
e definindo uma variável do resultado, digamos $ MAX ... a instrução sql pode então ser escrita"SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
minha sintaxe é baseada em phpSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
com variáveis MySQL.Crie uma tabela temporária com 100 linhas e uma única coluna contendo os valores 1-100.
Externo Junte esta tabela à sua tabela arrc_vouchers e selecione os valores de coluna única em que o id arrc_vouchers é nulo.
Codificar este cego, mas deve funcionar.
fonte
Uma solução alternativa que requer uma consulta + algum código fazendo algum processamento seria:
Observe que a consulta não contém nenhuma subseleção que sabemos que não é tratada de forma performante pelo planejador do MySQL.
Isso retornará uma entrada por centralValue (cValue) que não tem um valor menor (lValue) ou um valor maior (rValue), ou seja:
Sem entrar em mais detalhes (veremos nos próximos parágrafos), esta saída significa que:
Portanto, a ideia básica é fazer uma junção RIGHT e LEFT com a mesma tabela, vendo se temos valores adjacentes por valor (ou seja: se o valor central for '3', então verificamos 3-1 = 2 à esquerda e 3 + 1 em direita), e quando uma ROW tem um valor NULL em RIGHT ou LEFT, então sabemos que não há valor adjacente.
O resultado bruto completo da minha tabela é:
Algumas notas:
fonte
Se houver uma sequência com intervalo de no máximo um entre dois números (como 1,3,5,6), a consulta que pode ser usada é:
source1
id
fonte
com base na resposta dada acima por Lucek, este procedimento armazenado permite que você especifique os nomes da tabela e da coluna que deseja testar para encontrar registros não contíguos - respondendo assim à pergunta original e também demonstrando como se poderia usar @var para representar tabelas & / ou colunas em um procedimento armazenado.
fonte
Eu tentei -lo de diferentes maneiras e o melhor desempenho que eu encontrei foi esta consulta simples:
... uma junção à esquerda para verificar se o próximo id existe, apenas se next se não for encontrado, então a subconsulta encontra o próximo id que existe para encontrar o fim do gap. Fiz isso porque a consulta com igual (=) tem melhor desempenho do que maior que operador (>).
Usando o sqlfiddle ele não mostra um desempenho tão diferente de outras consultas, mas em um banco de dados real esta consulta acima resulta 3 vezes mais rápido do que outras.
O esquema:
Segue abaixo todas as consultas que fiz para comparar o desempenho:
Talvez ajude alguém e seja útil.
Você pode ver e testar minha consulta usando este sqlfiddle :
http://sqlfiddle.com/#!9/6bdca7/1
fonte
Embora tudo isso pareça funcionar, o conjunto de resultados retorna em muito tempo quando há 50.000 registros.
Eu usei isso, e ele encontra o gap ou o próximo disponível (último usado + 1) com um retorno muito mais rápido da consulta.
fonte
Provavelmente não é relevante, mas estava procurando algo assim para listar as lacunas em uma sequência de números e encontrei este post, que tem várias soluções diferentes dependendo exatamente do que você está procurando. Eu estava procurando a primeira lacuna disponível na sequência (ou seja, o próximo número disponível) e isso parece funcionar bem.
SELECT MIN (l.number_sequence + 1) como o próximo disponível de pacientes como l LEFT OUTER JOIN pacientes como r em l.number_sequence + 1 = r.number_sequence ONDE r.number_sequence é NULL. Vários outros cenários e soluções discutidos lá, a partir de 2005!
Como encontrar valores ausentes em uma sequência com SQL
fonte