Trouver le prochain id de libre.

Soyez le premier à donner votre avis sur cette source.

Snippet vu 8 739 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

cs_depression
Messages postés
100
Date d'inscription
mardi 7 novembre 2000
Statut
Membre
Dernière intervention
13 juillet 2009
-
Berk, c'est crade.

Au lieu d'utiliser une clé primaire dans ta table, utilise une clé unique, ce sera plus rapide et moins affreux pour les performances.
coockiesch
Messages postés
2268
Date d'inscription
mercredi 27 novembre 2002
Statut
Membre
Dernière intervention
13 septembre 2013
3 -
Salut! :-)

Quelques conseils:

mysql_query est toujours suivi d'un test pour vérifier la bonne exécution de la requête:
$ret = mysql_query( "SELECT ...." );
if( !$ret )
// traitement de l'erreur, on ne va pas plus loin

Ou, idem:
if( !( $ret = mysql_query( "SELECT ..." ) ) )
// traitement de l'erreur, on ne va pas plus loin

Ca évite des erreurs sur mysql_num_rows, mysql_fetch_*, ...

Si tu as le choix, privilégie ' ' à " ".

// ---- ICI on ferai un RETURN de l'ID si on fais une fonction ----
>> Justement, tu pourrais proposer une fonction, non? :-)

@++

R@f
SuperTonic
Messages postés
53
Date d'inscription
mercredi 24 juillet 2002
Statut
Membre
Dernière intervention
16 mars 2011
-
Bonjour.
Merci de ta réponse constructive.
Au bout de ma chaine (caché en fait par la form se trouve la chaine " or die(mysql_error()); "
qui reviens à ton " if( !$ret ) "

Pour la fonction, je suis en train de la faire.
Je la post dés qu'elle est terminée. (Je laisserai par contre les ECHO mais en commentaires)
Je sais que ça allourdi l'affichage, mais on est bien content de les trouver quand on essai de comprendre.
A bientot donc.
SuperTonic
Messages postés
53
Date d'inscription
mercredi 24 juillet 2002
Statut
Membre
Dernière intervention
16 mars 2011
-
IDEM mais sous la forme de 2 fonctions.
---------------------------------------------------------
function maxid($table, $id_contact)
{
//en fonction de la table les reqêtes différent un peu
switch($table)
{
case 'contacts':
$requete= "SELECT max(id_contact) FROM $table WHERE id_user='{$_SESSION['id_user']}'";
break;
default:
$requete="SELECT max(id) FROM $table WHERE id_contact='$id_contact' AND id_user='{$_SESSION['id_user']}'";
}

//on recherche le prochain id pour cette adresse
@mysql_free_result($result);
//echo $requete;
$result=mysql_query($requete,$_SESSION['linkdb']);
if (!$result) {die('Erreur num: '.mysql_errno($_SESSION['linkdb']).'
Échec de la requête : inF_nextid
('.$requete.'): '.mysql_error()); }
$val= @mysql_result($result, 0);
$max=$val+1;
return $max ;
}

---------------------------------------------------------
---------------------------------------------------------

function nextid($table, $id_contact)
{
// On recherche le MAX (appel Fonct.1)
$MAX= maxid($table, $id_contact);
//echo "Val MAX: $MAX
";

switch($table)
{
case 'contacts':
$requetesub=mysql_query("SELECT id_contact as id FROM $table WHERE id_user='{$_SESSION['id_user']}' ORDER by id_contact ASC") or die('Erreur num: '.mysql_errno($_SESSION['linkdb']).'
Échec de la requête : inF_nextid1
('.$req.'): '.mysql_error());
break;
default:
$requetesub=mysql_query("SELECT id FROM $table WHERE id_contact='$id_contact' AND id_user='{$_SESSION['id_user']}' ORDER by id ASC") or die('Erreur num: '.mysql_errno($_SESSION['linkdb']).'
Échec de la requête : inF_nextid2
('.$req.'): '.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
// uniquement si on exécute le While précédent mis en comment.
//mysql_data_seek($requetesub, 0);

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

while($i<$MAX)
{
$i++;
//echo "
Test de la valeur : {$i}
";
$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++;
if($p==$MAX)
{
return $MAX;
}else{
mysql_data_seek($requetesub, $p);
}
} else {
//echo"ID libre trouvé : $i ($val =$i)";
//on ne déplace pas le pointeur
mysql_data_seek($requetesub, $p);
return $i;
}
}
}

Bon courage à tous.
coockiesch
Messages postés
2268
Date d'inscription
mercredi 27 novembre 2002
Statut
Membre
Dernière intervention
13 septembre 2013
3 -
Ok, désolé, j'avais pas vu! :-)
Par contre, si tu fais une fonction, il peut être intéressant de ne pas faire le or die, mais de renvoyer une valeur spéciale...

@++

R@f

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.