131 votes

Comment trouver un "trou" dans l'exécution d'un compteur avec SQL?

Je voudrais trouver le premier "écart" dans une colonne de compteur dans la table SQL. Par exemple, s’il existe des valeurs 1, 2, 4 et 5, je voudrais savoir 3.

Je peux bien sûr mettre les valeurs en ordre et les parcourir manuellement, mais j'aimerais savoir s'il serait possible de le faire en SQL.

De plus, il devrait s'agir de SQL assez standard, fonctionnant avec différents SGBD.

218voto

Quassnoi Points 191041

En MySQL et PostgreSQL :

 SELECT  id + 1
FROM    mytable mo
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    mytable mi 
        WHERE   mi.id = mo.id + 1
        )
ORDER BY
        id
LIMIT 1
 

En SQL Server :

 SELECT  TOP 1
        id + 1
FROM    mytable mo
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    mytable mi 
        WHERE   mi.id = mo.id + 1
        )
ORDER BY
        id
 

En Oracle :

 SELECT  *
FROM    (
        SELECT  id + 1 AS gap
        FROM    mytable mo
        WHERE   NOT EXISTS
                (
                SELECT  NULL
                FROM    mytable mi 
                WHERE   mi.id = mo.id + 1
                )
        ORDER BY
                id
        )
WHERE   rownum = 1
 

ANSI (fonctionne partout, moins efficace):

 SELECT  MIN(id) + 1
FROM    mytable mo
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    mytable mi 
        WHERE   mi.id = mo.id + 1
        )
 

14voto

Ruben Points 41

Vos réponses fonctionnent toutes correctement si vous avez une première valeur id = 1, sinon cet espace ne sera pas détecté. Par exemple, si les valeurs de votre identifiant de table sont 3,4,5, vos requêtes renverront 6.

J'ai fait quelque chose comme ça

 SELECT MIN(ID+1) FROM (
    SELECT 0 AS ID UNION ALL 
    SELECT  
        MIN(ID + 1)
    FROM    
        TableX) AS T1
WHERE
    ID+1 NOT IN (SELECT ID FROM TableX) 
 

10voto

chaos Points 69029

Il n’existe pas vraiment de méthode SQL extrêmement standard, mais vous pouvez le faire avec une clause restrictive.

 SELECT `table`.`num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
LIMIT 1
 

(MySQL, PostgreSQL)

ou

 SELECT TOP 1 `num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
 

(Serveur SQL)

ou

 SELECT `num` + 1
FROM `table`
LEFT JOIN `table` AS `alt`
ON `alt`.`num` = `table`.`num` + 1
WHERE `alt`.`num` IS NULL
AND ROWNUM = 1
 

(Oracle)

9voto

La première chose qui me vint à l’esprit. Je ne sais pas si c'est une bonne idée de suivre cette voie, mais cela devrait fonctionner. Supposons que la table est t et la colonne est c :

SELECT t1.c+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL ORDER BY gap ASC LIMIT 1

Edit: Celui-ci peut être une tique plus rapide (et plus courte!):

SELECT min(t1.c)+1 AS gap FROM t as t1 LEFT OUTER JOIN t as t2 ON (t1.c+1=t2.c) WHERE t2.c IS NULL

6voto

Mayo Points 5532

Cela fonctionne dans SQL Server - impossible de le tester sur d'autres systèmes, mais cela semble être la norme ...

 SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1))
 

Vous pouvez également ajouter un point de départ à la clause where ...

 SELECT MIN(t1.ID)+1 FROM mytable t1 WHERE NOT EXISTS (SELECT ID FROM mytable WHERE ID = (t1.ID + 1)) AND ID > 2000
 

Donc, si vous aviez 2000, 2001, 2002 et 2005 alors que 2003 et 2004 n'existaient pas, il renverrait 2003.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X