web-dev-qa-db-fra.com

Trouver le prochain identifiant disponible dans MySQL

Je dois trouver le prochain identifiant disponible (s'il y a 5 données dans la base de données, je dois obtenir le prochain emplacement d'insertion disponible qui est 6) dans une base de données MySQL. Comment puis-je faire cela? J'ai utilisé MAX(id), mais lorsque je supprime certaines lignes de la base de données, celle-ci contient toujours l'ancienne valeur max.

47
Burak Dede

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

19
Simon Groenewolt

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

Le plus court que j'ai trouvé sur le site de développement mysql:

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

remarquez que si vous avez peu de bases de données avec les mêmes tables, vous devez également spécifier le nom de la base de données, comme suit:

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

En plus de la réponse de Lukasz Lysik - type de SQL LEFT-JOIN.
Si je comprends bien, si vous avez un identifiant: 1,2,4,5, il devrait renvoyer 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, même si les publications sont plutôt anciennes.

17
Jarry

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

mon identifiant de colonne est incrémenté automatiquement, je dois obtenir l'identifiant et le convertir en une autre base.Il me faut donc obtenir l'identifiant suivant avant que le code converti ne soit inséré car celui-ci sera inséré.

Il existe un moyen de faire ce que vous demandez, à savoir demander à la table ce que le l'identifiant de la prochaine ligne insérée sera être} avant que vous insériez réellement

SHOW TABLE STATUS WHERE name = "myTable"

il y aura un champ dans cet ensemble de résultats appelé "Auto_increment" qui vous indiquera la prochaine valeur d'incrémentation automatique.

10
nickf

Si j'ai bien compris, si vous avez un identifiant: 1,2,4,5, il devrait en retourner 3.

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

tu as dit:

mon identifiant est automatiquement incrémenté. pour obtenir l'identifiant et le convertir en une autre base.Alors il me faut le prochain id avant insertion cause le code converti sera inséré aussi.

ce que vous demandez est très dangereux et conduira à une situation de compétition. si votre code est exécuté deux fois simultanément par différents utilisateurs, ils obtiendront tous les deux la valeur 6 et leurs mises à jour ou insertions se superposeront.

je vous suggère plutôt de placer INSERT dans la table, d'obtenir la valeur auto_increment à l'aide de LAST_INSERT_ID(), puis UPDATE la ligne pour définir la valeur que vous avez qui dépend de la valeur auto_increment.

4
longneck

Si vous voulez sélectionner le premier espace, 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 la même requête avec la syntaxe ANSI:

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 du bogue d'optimiseur dans MySQL.

3
Quassnoi

Il est trop tard pour répondre à cette question maintenant, mais espérons 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'
1
Jay Bhatt

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

SELECT MAX(id) + 1 FROM table

Mais je suggérerais que vous laissiez MySQL créer l'identifiant lui-même (en utilisant une colonne à incrémentation automatique) et en utilisant LAST_INSERT_ID() pour le récupérer à partir du SGBD. Pour ce faire, utilisez une transaction dans laquelle vous exécutez l'insertion, puis interrogez l'id de la manière suivante:

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

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

1
Xperimental

Si ceci est utilisé conjointement pour INSÉRER un nouvel enregistrement, vous pouvez utiliser quelque chose comme ceci.

(Vous avez indiqué dans vos commentaires que l'identifiant est incrémenté automatiquement et que l'autre table nécessite l'identifiant suivant + 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
)

C'est un pseudocode mais vous avez l'idée

0
Phill Pafford

Une façon de le faire est de définir l'index pour l'incrémentation automatique. Ensuite, votre instruction SQL spécifie simplement NULL, puis l’analyseur SQL se charge du reste.

INSERT INTO foo VALUES (null);
0
gshauger