Trouver le prochain id de libre.

Soyez le premier à donner votre avis sur cette source.

Snippet vu 8 822 fois - Téléchargée 17 fois

Contenu du snippet

MON PROBLEME ETAIT :

Dans mes tables de ma base de données, j'ai les valeurs suivantes. ces valeurs valent d'ID.
Pour des raisons de facilités, ces id ne sont pas en auto-Incrément.

Par défaut pour insérer un nouvel élément je fais un max(id) +1

Mais reprenons mon histoire ...
J'ai donc les valeurs :
1 - 2 - 3 - 4 - 5 - 6 - 7

Je delete le [4] et le [6] par exemple.

A l'insert suivant, comme a l'habitude je fais un max(id)+1.
Ce qui en toute logique me renvoi 8.

Mais voilà, j'aimerai que ça me renvoi tout d'abord [4], puis le [6] avant le [8].
En gros je souhaite combler les "trous" ...
___________________________________________________________________________________

J'ai trouvée une solution qui fonctionne bien. Le code qui suit est commenté et remplis de ECHO, afin de bien comprendre le cheminement.
Il est bien sûr a améliorer, à nettoyer etc ...
Mais je suis sur qu'il servira à des personnes comme moi, qui ont longuement cherché une instruction Mysql...

Avec un peu d'idée, on peut en faire une fonction, multi table qui renvoi simplement l'ID suivant dispo.

Source / Exemple :


//Chaine de connexion à la Bdd ici
include("connect.php");

// On recherche le MAX
$result=mysql_query("SELECT max(id) FROM matable WHERE cid='6' AND uid='1' ORDER by id ASC") or die(mysql_error());
$MAX= @mysql_result($result, 0);
echo "Nb Val. ( val MAX) : $MAX (prochain serait $MAX + 1 )<br>";
echo "<hr>";

// On regarde les valeurs qui existent dans la table
$requetesub=mysql_query("SELECT id FROM matable WHERE cid='6' AND uid='1' ORDER by id ASC") or die(mysql_error());
$totalsub = mysql_num_rows($requetesub);

// Pour info/test on affiche des résultats
echo "$totalsub ID relemnt occupé ( ";
while ($row = mysql_fetch_array($requetesub, MYSQL_ASSOC)) {
   echo " {$row['id']} ";
}
echo")<hr>";

//On remet le pointeur au début. afin de parcourir de nouveau le tableau
mysql_data_seek($requetesub, 0);

$i=-1; //(-1 pour tester la valeur 0)
$p=0; //sera le pointeur.

while($i<$MAX)
 {
   $i++;
   echo "<br> <u><b>Test de la valeur</u> : {$i} </b><br>";
   $row = mysql_fetch_array($requetesub, MYSQL_ASSOC);
   $val = $row['id'];
   
   if($val==$i)
    {
      echo"La valeur est = à i -> la preuve :($val=$i)";
      //on bouge le pointeur d'1 point
      $p++;
      @mysql_data_seek($requetesub, $p);
      // A ce niveau, à la dern. valeur on aura une erreur de dépassement.
      // Il faut donc prévoir un petit changement ou un test sup.
      // Le @ évite simplement l'affichage du message d'erreur.
    
    } else {
      echo"ID libre trouvé : <b>$i</b> ($val=$i)";
      //on ne déplace pas le pointeur
      mysql_data_seek($requetesub, $p);
      // ---- ICI on ferai un RETURN de l'ID si on fais une fonction ----

    }

  echo"<hr>";
}

Conclusion :


Je précise que ma clé est de ce type :
Pour chaque $GID il exsite 0 à plusieurs $CID
Chaque $CID ayant de 0àn $ID

Plus clairement :
GID CID ID
1 1 1
1 1 1
1 1 2
1 2 1
1 2 1
1 2 4
1 2 5
1 2 6
1 3 1
etc...

A voir également

Ajouter un commentaire

Commentaires

Messages postés
1
Date d'inscription
lundi 28 mars 2005
Statut
Membre
Dernière intervention
19 septembre 2007

Bonjour à tous,

Je rajouterai, au fait que ça n'a aucun intêret de boucher les trous dans les id, que cela ne peut amener que des problèmes surtout s'il y a plusieurs utilisateurs qui saisissent des données en même temps :
le même id (max id+1) peut etre attribué plusieurs fois à des utilisateurs différents, tant qu'il n'aurra pas été enregistré dans la bd, et donc lors de l'enregistrement pour les utilisateurs suivants, des doublons ou des blocages à l'insert peuvent apparaître suivant la nature de la cle concernée (unique ou pas)...
Quand à moi je préfère laisser mysql gérer ça tous seul...c'est son job...
... peu-etre penser aussi à last_insert()
bonne continuation
Messages postés
53
Date d'inscription
mercredi 24 juillet 2002
Statut
Membre
Dernière intervention
16 mars 2011

Ok !! j'ai compris... Je vais lire cette doc.
Je vais également ajouté des LIMIT à mes requêtes....
Messages postés
1980
Date d'inscription
dimanche 20 février 2005
Statut
Membre
Dernière intervention
24 septembre 2012
5
Merci pour ton article Coucou.
Pour les benchmarks, pourquoi ne pas faire la somme du temps d'exécution de 100 000 instructions ? On y verrait plus clair. Le nombre ROWS de EXPLAIN n'est pas significatif, ça ne veut pas dire que MySQL va parcourir plus de lignes pour un > + LIMIT. C'est uniquement le nombre de résultats possibles, point.

Ta conclusion qui est de dire qu'ordonner une table selon l'ordre où les lignes sont les plus sollicitées me paraît tout à fait logique. Ca revient à faire ORDER une seule fois et pas à chaque SELECT. Sauf que j'en reviens au problème de base :

1) ce n'est pas le métier de la clé primaire de servir pour l'ordre. D'ailleurs une nouvelle ligne vient prendre un id libre au pif, en tout cas dans cette source.
2) sous MyIsam, la clé primaire ne définit PAS l'ordre des lignes dans la table. Une nouvelle ligne ne sera pas accédée plus vite qu'elle porte l'id 3 ou l'id 265972545.

Donc fondamentalement, boucher les trous des ID ne sert à rien et causent des pbs. Ensuite si tu veux réordonner ta table à chaque insertion, libre à toi, ça peut être un choix judicieux dans certains cas précis, mais il n'y a pas de rapport avec le fait de boucher les id libres.

Je signale quand même qu'avec ta technique Coucou, je pense que tu ne peux pas utiliser de clé index, puisqu'au moment de la recherche ça viendrait à l'encontre de la façon dont tu as réordonné ta table par toi-même. Ce qui est coûteux pour toutes les requêtes autres que ta (ton unique) requête optimisée. A moins qu'il soit possible de spécifier quand on fait un SELECT de tenir compte ou pas des colonnes indexées ? Mais je n'en ai jamais entendu parler.

SuperTonic : tout simplement, si tu fais SELECT name where id 5; MySQL va trouver la ligne, puis continuer pour voir s'il n'y en a pas d'autre ou id 5. Ce qui est idiot parce que tu sais que chaque id et unique, donc il nen trouvera rien. Avec LIMIT tu lui dit d'arrêter de chercher.
Tu peux aller lire la doc officielle de MySQL, il y a un chapitre entier sur l'optimisation.
Messages postés
12303
Date d'inscription
mardi 10 février 2004
Statut
Modérateur
Dernière intervention
30 juillet 2012
38
je viens de vous faire un bench...
http://blogs.codes-sources.com/coucou747/archive/2007/09/14/bench-sur-la-pagination-sous-mysql.aspx
mais meme ton WHERE + limit, ca revient a faire :
WHERE champ_dans_l_ordre >= page*nbr_par_page LIMIT nbr_par_page
donc ton champ doit-etre dans l'ordre...
le explain semble indiquer que... les benchs sont toutefois plus reserves...
Messages postés
240
Date d'inscription
vendredi 14 juin 2002
Statut
Membre
Dernière intervention
17 mars 2009

Cette fonction est là pour trouver le prochain id, elle ne réorganise pas les enregistrements. Elle n'est donc pas à exécuter après un delete mais avant un insert.

@SuperTonic : Si tu indiques correctement les conditions, oui. C'est important (mais pas indispensable) car il permet de ne pas mobiliser plus de ressources que nécessaire. C'est de l'optimisation. Pourquoi charger en mémoire tous les enregistrements quand tu n'as besoin que des 10 premiers, ou que du 11ème au 20ème (par exemple...) ?
Afficher les 23 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.