Nous avons une base de données avec une table dont les valeurs ont été importées d'un autre système. Il existe une colonne à incrémentation automatique et aucune valeur en double, mais des valeurs manquantes. Par exemple, en exécutant cette requête:
select count(id) from arrc_vouchers where id between 1 and 100
devrait renvoyer 100, mais il renvoie 87 à la place. Y a-t-il une requête que je peux exécuter qui renverra les valeurs des nombres manquants? Par exemple, les enregistrements peuvent exister pour les identifiants 1-70 et 83-100, mais il n'y a pas d'enregistrements avec des identifiants 71-82. Je veux retourner 71, 72, 73, etc.
Est-ce possible?
mysql
sql
gaps-and-islands
EmmyS
la source
la source
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;
Réponses:
Mettre à jour
ConfexianMJS a fourni une bien meilleure réponse en termes de performances.
La réponse (pas aussi rapide que possible)
Voici la version qui fonctionne sur une table de toute taille (pas seulement sur 100 lignes):
gap_starts_at
- premier identifiant dans l'écart actuelgap_ends_at
- dernier identifiant dans l'intervalle actuella source
order number
je recherchais des lacunes dans n'est pas distinct (le tableau stocke les lignes de commande, donc le numéro de commande auquel elles appartiennent se répète pour chaque ligne). 1ère requête: 2812 lignes dans l'ensemble (1 min 31,09 s) . Fabriqué une autre table en sélectionnant des numéros de commande distincts. Votre requête sans mes répétitions: 1009 lignes dans l'ensemble (18,04 sec)SELECT MIN(id) FROM table
?Cela a fonctionné pour moi pour trouver les lacunes dans un tableau avec plus de 80 000 lignes:
Résultat:
Notez que l'ordre des colonnes
expected
etgot
est critique.Si vous savez que
YourCol
cela ne commence pas à 1 et que cela n'a pas d'importance, vous pouvez remplaceravec
Nouveau résultat:
Si vous devez effectuer une sorte de tâche de script shell sur les ID manquants, vous pouvez également utiliser cette variante afin de produire directement une expression sur laquelle vous pouvez itérer dans bash.
Cela produit une sortie comme celle-ci
Vous pouvez ensuite le copier et le coller dans une boucle for dans un terminal bash pour exécuter une commande pour chaque ID
C'est la même chose que ci-dessus, mais c'est à la fois lisible et exécutable. En modifiant la commande "CONCAT" ci-dessus, la syntaxe peut être générée pour d'autres langages de programmation. Ou peut-être même SQL.
la source
CONVERT( YourCol, UNSIGNED )
cela donnera de meilleurs résultats si YourCol n'est pas déjà un entier.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;
Requête rapide et sale qui devrait faire l'affaire:
Cela vous donnera un tableau montrant l'id qui a des identifiants manquants au-dessus, et next_id qui existe, et combien sont manquants entre ...
la source
Si vous utilisez un,
MariaDB
vous disposez d'une option plus rapide (800%) utilisant le moteur de stockage de séquence :la source
"SELECT MAX(column) FROM table"
et en définissant une variable à partir du résultat, disons $ MAX ... l'instruction sql peut alors être écrite"SELECT * FROM seq_1_to_". $MAX ." WHERE seq not in (SELECT column FROM table)"
ma syntaxe est basée sur phpSELECT @var:= max FROM ....; select * from .. WHERE seq < @max;
avec des variables MySQL.Créez une table temporaire avec 100 lignes et une seule colonne contenant les valeurs 1 à 100.
Externe Joignez cette table à votre table arrc_vouchers et sélectionnez les valeurs de colonne unique où l'id arrc_vouchers est nul.
Coder ce aveugle, mais devrait fonctionner.
la source
Une solution alternative qui nécessite une requête + du code effectuant un traitement serait:
Notez que la requête ne contient aucune sous-sélection dont nous savons qu'elle n'est pas gérée de manière performante par le planificateur de MySQL.
Cela renverra une entrée par centralValue (cValue) qui n'a pas une valeur plus petite (lValue) ou une valeur plus grande (rValue), c'est-à-dire:
Sans entrer dans plus de détails (nous les verrons dans les paragraphes suivants), cette sortie signifie que:
L'idée de base est donc de faire une jointure DROITE et GAUCHE avec la même table pour voir si nous avons des valeurs adjacentes par valeur (c'est-à-dire: si la valeur centrale est '3' alors nous vérifions 3-1 = 2 à gauche et 3 + 1 à right), et quand une ROW a une valeur NULL à RIGHT ou LEFT, nous savons qu'il n'y a pas de valeur adjacente.
La sortie brute complète de ma table est:
Quelques notes:
la source
S'il y a une séquence ayant un écart de maximum un entre deux nombres (comme 1, 3, 5, 6) alors la requête qui peut être utilisée est:
source1
id
la source
basé sur la réponse donnée ci-dessus par Lucek, cette procédure stockée vous permet de spécifier les noms de table et de colonne que vous souhaitez tester pour trouver des enregistrements non contigus - répondant ainsi à la question d'origine et démontrant également comment on pourrait utiliser @var pour représenter des tables & / ou colonnes dans une procédure stockée.
la source
Je l'ai essayé de différentes manières et la meilleure performance que j'ai trouvée était cette simple requête:
... une jointure gauche pour vérifier si le prochain identifiant existe, seulement si le suivant s'il n'est pas trouvé, alors la sous-requête trouve l'identifiant suivant qui existe pour trouver la fin de l'écart. Je l'ai fait car une requête avec égal (=) est de meilleures performances que l' opérateur supérieur à (>).
En utilisant sqlfiddle , les performances des autres requêtes ne sont pas si différentes, mais dans une base de données réelle, cette requête ci-dessus résulte 3 fois plus rapidement que les autres.
Le schéma:
Suivez ci-dessous toutes les requêtes que j'ai faites pour comparer les performances:
Peut-être que cela aide quelqu'un et utile.
Vous pouvez voir et tester ma requête en utilisant ce sqlfiddle :
http://sqlfiddle.com/#!9/6bdca7/1
la source
Bien que tous semblent fonctionner, le jeu de résultats retourne très longtemps lorsqu'il y a 50 000 enregistrements.
Je l'ai utilisé, et il trouve l'écart ou le prochain disponible (dernier utilisé + 1) avec un retour beaucoup plus rapide de la requête.
la source
Probablement pas pertinent, mais je cherchais quelque chose comme celui-ci pour répertorier les lacunes dans une séquence de nombres et j'ai trouvé ce post, qui propose plusieurs solutions différentes en fonction exactement de ce que vous recherchez. Je cherchais le premier espace disponible dans la séquence (c'est-à-dire le prochain numéro disponible), et cela semble fonctionner correctement.
SELECT MIN (l.number_sequence + 1) comme prochainavabile des patients comme l LEFT OUTER JOIN patients comme r sur l.number_sequence + 1 = r.number_sequence WHERE r.number_sequence est NULL. Plusieurs autres scénarios et solutions y discutés, à partir de 2005!
Comment rechercher des valeurs manquantes dans une séquence avec SQL
la source