Trouver le prochain identifiant disponible dans MySQL

Je dois trouver le prochain identifiant disponible (s’il y a 5 données dans la firebase database, je dois obtenir le prochain emplacement d’insertion disponible qui est 6) dans une firebase database MySQL. Comment puis je faire ça? J’ai utilisé MAX(id) , mais lorsque je supprime des lignes de la firebase database, il contient toujours l’ancienne valeur max qu’il n’a pas mise à jour.

Je ne pense pas que vous puissiez être sûr du prochain identifiant, car quelqu’un pourrait insérer une nouvelle ligne juste après avoir demandé le prochain identifiant. Vous auriez au moins besoin d’une transaction, et si je ne me trompe pas, vous ne pouvez obtenir l’ID réel utilisé qu’après l’avoir inséré, du moins c’est la manière habituelle de le gérer – voir http://dev.mysql.com/ doc / refman / 5.0 / fr / getting-unique-id.html

Mise à jour 2014-12-05: Je ne recommande pas cette approche pour des raisons exposées dans la réponse de Simon (acceptée) ainsi que dans le commentaire de Diego. Veuillez utiliser la requête ci-dessous à vos risques et périls.

Le plus court que j’ai trouvé sur le site de développeur mysql:

 SELECT Auto_increment FROM information_schema.tables WHERE table_name='the_table_you_want' 

Si vous avez peu de bases de données avec les mêmes tables, vous devez également spécifier le nom de la firebase database, comme ceci:

 SELECT Auto_increment FROM information_schema.tables WHERE table_name='the_table_you_want' AND table_schema='the_database_you_want'; 

En plus de la réponse de Lukasz Lysik – SQL de type LEFT-JOIN.
Si je comprends bien, si ont id: 1,2,4,5 il devrait retourner 3.

 SELECT u.Id + 1 AS FirstAvailableId FROM users u LEFT JOIN users u1 ON u1.Id = u.Id + 1 WHERE u1.Id IS NULL ORDER BY u.Id LIMIT 0, 1 

J’espère que cela aidera certains visiteurs, bien que les postes soient plutôt vieux.

Compte tenu de ce que vous avez dit dans un commentaire:

mon identifiant est un incrément automatique, je dois obtenir l’identifiant et le convertir en une autre base. Je dois donc obtenir le prochain identifiant avant l’insertion car le code converti sera inséré aussi.

Il y a un moyen de faire ce que vous demandez, qui consiste à demander à la table quel sera l’ identifiant de la prochaine ligne insérée avant de l’insérer:

 SHOW TABLE STATUS WHERE name = "myTable" 

il y aura un champ dans cet ensemble de résultats appelé “Auto_increment” qui vous indique la prochaine valeur d’incrémentation automatique.

Si je comprends bien, si ont id: 1,2,4,5 il devrait retourner 3.

 SELECT t1.id + 1 FROM theTable t1 WHERE NOT EXISTS ( SELECT * FROM theTable t2 WHERE t2.id = t1.id + 1 ) LIMIT 1 

tu as dit:

mon identifiant est un incrément automatique, je dois obtenir l’identifiant et le convertir en une autre base. Je dois donc obtenir le prochain identifiant avant l’insertion car le code converti sera inséré aussi.

Ce que vous demandez est très dangereux et conduira à une condition de course. Si votre code est exécuté deux fois en même temps par des utilisateurs différents, ils obtiendront tous deux 6 et leurs mises à jour ou insertions se chevaucheront.

Je suggère que vous INSERT plutôt à la table, obtenez la valeur LAST_INSERT_ID() utilisant LAST_INSERT_ID() , puis UPDATE la ligne pour définir la valeur que vous avez qui dépend de la valeur auto_increment.

Si vous souhaitez sélectionner le premier intervalle, utilisez ceci:

 SELECT @r FROM ( SELECT @r := MIN(id) - 1 FROM t_source2 ) vars, t_source2 WHERE (@r := @r + 1) <> id ORDER BY id LIMIT 1; 

Il existe une version de syntaxe ANSI de la même requête:

 SELECT id FROM mytable mo WHERE ( SELECT id + 1 FROM mytable mi WHERE mi.id < mo.id ORDER BY mi.id DESC LIMIT 1 ) <> id ORDER BY id, LIMIT 1 

Cependant, il sera lent en raison d’un bogue d’optimisation dans MySQL .

Si vous voulez vraiment calculer la clé de l’insertion suivante avant d’insérer la ligne (ce qui, à mon avis, n’est pas une très bonne idée), alors je vous suggère d’utiliser l’identifiant maximum actuellement utilisé plus un:

 SELECT MAX(id) + 1 FROM table 

Mais je vous suggère de laisser MySQL créer lui-même l’ID (en utilisant une colonne à auto-incrémentation) et d’utiliser LAST_INSERT_ID() pour l’obtenir du SGBD. Pour ce faire, utilisez une transaction dans laquelle vous exécutez l’insertion, puis interrogez l’ID comme suit:

 INSERT INTO table (col1) VALUES ("Text"); SELECT LAST_INSERT_ID(); 

Le returnset ne contient plus qu’une colonne contenant l’identifiant de la nouvelle ligne générée.

Il est trop tard pour répondre à cette question maintenant, mais j’espère que cela aidera quelqu’un.

@Eimantas a déjà donné la meilleure réponse, mais la solution ne fonctionnera pas si vous avez deux tables ou plus du même nom sous le même serveur.

J’ai légèrement modifié la réponse de @ Eimantas pour résoudre le problème ci-dessus.

 select Auto_increment as id from information_schema.tables where table_name = 'table_name' and table_schema = 'database_name' 

Une façon de le faire est de définir l’indexation automatique de l’index. Ensuite, votre instruction SQL spécifie simplement NULL, puis SQL parser fait le rest pour vous.

 INSERT INTO foo VALUES (null); 

Si cette option est utilisée conjointement pour insérer un nouvel enregistrement, vous pouvez utiliser quelque chose comme ceci.

(Vous avez déclaré dans vos commentaires que l’identifiant est auto-incrémenté et que l’autre table a besoin du prochain ID + 1)

 INSERT INTO TABLE2 (id, field1, field2, field3, etc) VALUES( SELECT (MAX(id) + 1), field1, field2, field3, etc FROM TABLE1 WHERE condition_here_if_needed ) 

Ceci est un pseudocode mais vous avez l’idée

Le problème avec beaucoup de solutions est qu’ils ne trouvent que le prochain “GAP”, en ignorant si “1” est disponible, ou s’il n’y a pas de lignes, ils retourneront NULL comme prochain “GAP”.

Les éléments suivants trouveront non seulement le prochain intervalle disponible, mais ils prendront également en compte si le premier numéro disponible est 1:

 SELECT CASE WHEN MIN(MyID) IS NULL OR MIN(MyID)>1 -- return 1 if it's available or if there are no rows yet THEN 1 ELSE -- find next gap (SELECT MIN(t.MyID)+1 FROM MyTable t (updlock) WHERE NOT EXISTS (SELECT NULL FROM MyTable n WHERE n.MyID=t.MyID+1)) END AS NextID FROM MyTable 

Cela a bien fonctionné pour moi (MySQL 5.5), résolvant également le problème de la position de départ.

 SELECT IF(res.nextID, res.nextID, @r) AS nextID FROM (SELECT @r := 30) AS vars, ( SELECT MIN(t1.id + 1) AS nextID FROM test t1 LEFT JOIN test t2 ON t1.id + 1 = t2.id WHERE t1.id >= @r AND t2.id IS NULL AND EXISTS ( SELECT id FROM test WHERE id = @r ) LIMIT 1 ) AS res LIMIT 1 

Comme mentionné précédemment, ces types de requêtes sont très lents, du moins dans MySQL.

 SELECT ID+1 "NEXTID" FROM ( SELECT ID from TABLE1 WHERE ID>100 order by ID ) "X" WHERE not exists ( SELECT 1 FROM TABLE1 t2 WHERE t2.ID=X.ID+1 ) LIMIT 1 
 connectDB(); } private function connectDB(){ $this->link = new mysqli($this->host, $this->user, $this->pass, $this->dbname); if(!$this->link){ $this->error ="Connection fail".$this->link->connect_error; return false; } } // Select or Read data public function select($query){ $result = $this->link->query($query) or die($this->link->error.__LINE__); if($result->num_rows > 0){ return $result; } else { return false; } } } $db = new Database(); $query = "SELECT * FROM table_name WHERE id > '$current_postid' ORDER BY ID ASC LIMIT 1"; $postid = $db->select($query); if ($postid) { while ($result = $postid->fetch_assoc()) { echo $result['id']; } } ?>