Comment trouver des lacunes dans la numérotation séquentielle dans mysql?
Nous avons une base de données avec une table dont les valeurs ont été importés à partir d'un autre système. Il s'agit d'une auto-incrémentée, et il n'y a pas de doublons, mais il y a des valeurs manquantes. Par exemple, l'exécution de cette requête:
select count(id) from arrc_vouchers where id between 1 and 100
devrait revenir à 100, mais il renvoie 87 au lieu de cela. Est-il une requête je peux courir qui retourne les valeurs des nombres manquants? Par exemple, les enregistrements peuvent exister pour id 1-70 et 83-100, mais il n'y a pas d'enregistrements avec l'identité de 71-82. Je veux retourner 71, 72, 73, etc.
Est-ce possible?
- Cela peut ne pas fonctionner dans MySQL, mais au travail (Oracle), nous avons besoin de quelque chose de similaire. Nous avons écrit une procédure Stockée qui a eu un certain nombre que la valeur Max. La procédure Stockée a ensuite créé une table temporaire avec une seule colonne. La table contient tous les chiffres de 1 à Max. Puis il a fait un PAS DANS la jointure entre la table temporaire et notre table d'intérêts. Si vous l'avez appelé avec Max = Select max(id) from arrc_vouchers, il serait alors retourner toutes les valeurs manquantes.
- Quel est le problème avec le fait d'avoir des lacunes dans la numérotation? La valeur d'une clé de substitution n'est généralement pas utile; tout ce qui compte c'est qu'il est unique. Si votre application ne peut pas gérer les non-contigus Id, qui est probablement un bug dans l'application, mais pas dans les données.
- Dans ce cas, c'est un problème parce que les données que nous avons hérités de l'ancien système de l'auto-incrémenter le numéro associé à un dossier comme une clé pour l'imprimer sur une carte physique qui est remis aux personnes. Ce n'était PAS notre idée. Afin de savoir quelles sont les cartes manquantes, nous avons besoin de savoir où sont les lacunes dans la numérotation séquentielle.
- xaprb.com/blog/2005/12/06/...
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;
- Vous pouvez utiliser générer des séries de générer des nombres de 1 à la plus haute id de votre table. Ensuite, exécutez une requête où l'id n'est pas dans cette série.
Vous devez vous connecter pour publier un commentaire.
Mise à jour
ConfexianMJS fourni beaucoup mieux réponse en termes de performances.
L' (pas aussi rapide que possible) réponse
Voici la version qui fonctionne sur le tableau de taille quelconque (et pas seulement sur les 100 lignes):
gap_starts_at
- id du premier dans le fossé actuelgap_ends_at
- dernier id dans le fossé actuelorder number
j'étais à la recherche pour les lacunes n'est pas distincte (la table stocke les lignes de commande, de sorte que le numéro d'ordre qu'ils appartiennent à répétitions pour chaque ligne). 1er de la requête: 2812 rows in set (1 min 31.09 s). Fait un autre tableau en sélectionnant distinctes numéros de commande. Votre requête sans que je le répète: 1009 rows in set (18.04 s)SELECT MIN(id) FROM table
?SELECT t1.id + 1 AS gap_starts_at FROM arrc_vouchers t1 LEFT JOIN arrc_vouchers t2 ON t1.id + 1 = t2.id HAVING t2.id IS NULL
? Le gap_ends_at devrait fonctionner à l'aide de la même sous-requête, trop paresseux pour écrire.Ce juste travaillé pour moi de trouver les lacunes dans une table avec plus de 80k lignes:
Résultat:
Notez que l'ordre des colonnes
expected
etgot
est critique.Si vous savez que
YourCol
de ne pas commencer à 1 et qui n'a pas d'importance, vous pouvez remplaceravec
Nouveau résultat:
Si vous avez besoin pour effectuer une sorte de script shell tâche sur les disparus Id, vous pouvez également utiliser cette variante, afin de produire directement une expression que vous pouvez parcourir en bash.
Ce qui produit une sortie comme
Vous pouvez ensuite copier et coller dans une boucle for dans un bash terminal pour exécuter une commande pour chaque ID
C'est la même chose que ci-dessus, seulement que c'est à la fois lisible et exécutable. En changeant le "CONCAT" commande ci-dessus, la syntaxe peut être généré pour d'autres langages de programmation. Ou peut-être même de SQL.
CONVERT( YourCol, UNSIGNED )
donnera de meilleurs résultats si YourCol n'est-ce pas déjà un entier.Rapide et Sale requête qui devrait faire l'affaire:
Cela vous donnera un tableau indiquant l'id a id manquant au-dessus d'elle, et next_id qui existe, et combien sont manquantes entre...par exemple
Si vous utilisez un
MariaDB
vous avez un plus rapide (800%) option à l'aide de la séquence moteur de stockage:"SELECT MAX(column) FROM table"
et la définition d'une variable de résultat en dire $MAX... l'instruction sql peut être écrite"SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
ma syntaxe est en phpSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
avec MySQL variables.Créer une table temporaire avec 100 lignes et une seule colonne contenant les valeurs de 1 à 100.
Jointure externe ce tableau à votre arrc_vouchers de la table et de sélectionner la colonne des valeurs où le arrc_vouchers id est null.
De codage des aveugles, mais devrait fonctionner.
Une solution alternative qui nécessite une requête + un peu de code en faisant un traitement serait:
Remarque que la requête ne contiennent pas de sous-sélection que nous savons qu'il n'est pas manipulé performantly par MySQL planner.
Qui sera de retour une entrée par centralValue (cValue) qui n'ont pas une valeur plus petite (lValue) ou une plus grande valeur (valeur r), c'est à dire:
Sans entrer dans les détails (nous le verrons dans les paragraphes suivants) cette sortie signifie que:
Donc l'idée de base est de faire du DROIT et GAUCHE rejoint à la même table pour voir si nous avons adjacents valeurs par la valeur (c'est à dire: si la valeur centrale est '3', puis nous vérifier 3-1=2, à gauche et 3+1 à droite), et lorsqu'une LIGNE a une valeur NULL à DROITE ou à GAUCHE alors nous savons qu'il n'est pas adjacent valeur.
Le raw complet sortie de ma table est:
Quelques remarques:
basée sur la réponse donnée ci-dessus par Lucek cette procédure stockée permet de spécifier la table et les noms de colonnes que vous souhaitez tester pour trouver des non-contigus de dossiers répondant ainsi à la question d'origine et également la démonstration de la façon dont on pourrait utiliser @var représenter les tables &/ou des colonnes dans une procédure stockée.
Si il y a une séquence d'avoir d'écart maximum entre deux numéros (comme
1,3,5,6), alors la requête qui peut être utilisé est:
source1
id
Bien que ces tous l'air de fonctionner, le jeu de résultats est de retour dans un temps très long quand il y a 50 000 enregistrements.
Je l'utilise, et de trouver l'écart ou de la suivante (la dernière utilisation + 1) avec une plus grande vitesse de retour de la requête.
Je essayé de différentes manières et de la meilleure performance que j'ai découvert cette requête simple:
... un left join pour vérifier si la prochaine id existe, uniquement si s'est pas trouvé, alors la sous-requête de trouver la prochaine id qui existe pour trouver la fin de gap. Je l'ai fait car requête avec l'égalité des (=) est de meilleures performances que plus de (>) de l'opérateur.
À l'aide de la sqlfiddle il pas voir si les différentes performances des autres requête, mais dans une vraie base de données cette requête ci-dessus 3 fois plus rapide que les autres.
Le schéma:
Suivre soufflet toutes les requêtes que j'ai effectué pour comparer la performance:
Peut-être que ça aide quelqu'un et utile.
Vous pouvez voir et tester ma requête à l'aide de cette sqlfiddle:
http://sqlfiddle.com/#!9/6bdca7/1
Probablement pas pertinentes, mais je cherchais quelque chose comme ça à la liste des lacunes dans une séquence de chiffres et trouvé ce post, qui dispose de plusieurs solutions différentes selon exactement ce que vous cherchez. J'ai été à la recherche pour la première lacune dans la séquence (i.e. numéro disponible suivant), et cela semble bien fonctionner.
SELECT MIN(l.number_sequence + 1) comme nextavabile de patients que l JOINTURE EXTERNE GAUCHE patients de r sur l'.number_sequence + 1 = r.number_sequence OÙ r.number_sequence est NULL. Plusieurs autres scénarios et des solutions, les débats, à partir de 2005 !
Comment Trouver les Valeurs Manquantes dans une Séquence Avec SQL