web-dev-qa-db-fra.com

mysql génération de numéro unique

Je veux générer une identité entière unique aléatoire (de 10000 à 99999) simplement en nettoyant mySQL; des idées?

Je ne veux pas générer ce nombre en php par cycle (générer un nombre -> vérifier dans la base de données) parce que je veux utiliser une solution intelligente dans une requête mySQL.

14
hippout

Bien que cela semble un peu gênant, voici ce qui peut être fait pour atteindre l'objectif:

SELECT FLOOR(10000 + Rand() * 89999) AS random_number
FROM table
WHERE random_number NOT IN (SELECT unique_id FROM table)
LIMIT 1

En termes simples, il génère N nombres aléatoires, où N est le nombre de lignes de la table, filtre celles qui sont déjà présentes dans la table et limite le jeu restant à un.

Cela pourrait être un peu lent sur les grandes tables. Pour accélérer les choses, vous pouvez créer une vue à partir de ces identifiants uniques et l'utiliser au lieu d'une instruction select imbriquée.

EDIT: citations supprimées

20
unclenorton

Construisez une table de correspondance à partir de nombres séquentiels en valeurs id aléatoires comprises entre 1 et 1M:

create table seed ( i int not null auto_increment primary key );
insert into seed values (NULL),(NULL),(NULL),(NULL),(NULL),
                        (NULL),(NULL),(NULL),(NULL),(NULL);

insert into seed select NULL from seed s1, seed s2, seed s3, seed s4, seed s5, seed s6;
delete from seed where i < 100000;

create table idmap ( n int not null auto_increment primary key, id int not null );
insert into idmap select NULL, i from seed order by Rand();

drop table seed;

select * from idmap limit 10;

+----+--------+
| n  | id     |
+----+--------+
|  1 | 678744 |
|  2 | 338234 |
|  3 | 469412 |
|  4 | 825481 |
|  5 | 769641 |
|  6 | 680909 |
|  7 | 470672 |
|  8 | 574313 |
|  9 | 483113 |
| 10 | 824655 |
+----+--------+
10 rows in set (0.00 sec)

(Tout cela prend environ 30 secondes à mon ordinateur portable. Vous n’auriez à le faire qu’une fois pour chaque séquence.)

Maintenant que vous avez le mappage, gardez simplement une trace du nombre d’utilisations (un champ de compteur ou de clé auto_increment dans une autre table).

5
Martin

J'ai eu du mal à trouver la solution ici pendant un moment, puis j'ai réalisé qu'elle échouait si la colonne contenait des entrées NULL. J'ai retravaillé ceci avec le code suivant;

SELECT FLOOR(10000 + Rand() * 89999) AS my_tracker FROM Table1 WHERE "tracker" NOT IN (SELECT tracker FROM Table1 WHERE tracker IS NOT NULL) LIMIT 1

Violon ici; http://sqlfiddle.com/#!2/620de1/1

J'espère que c'est utile :)

2
HeavyHead

La seule idée raisonnable à mi-chemin que je puisse trouver est de créer une table avec un pool fini d'identifiants et, au fur et à mesure de leur utilisation, supprimez-les de cette table. Ces clés peuvent être uniques et un script pourrait être créé pour générer cette table. Vous pouvez ensuite tirer une de ces clés en générant une sélection aléatoire parmi les clés disponibles. J'ai dit «à mi-chemin» raisonnable et honnêtement, c'était trop généreux, mais cela bat des clés au hasard jusqu'à ce que vous en créiez une unique, je suppose.

1
James

Ma solution, implémentée dans Cakephp 2.4.7, consiste à créer une table avec un champ de type auto_incremental

CREATE TABLE `unique_counters` (
  `counter` int(11) NOT NULL AUTO_INCREMENT,
  `field` int(11) NOT NULL,
  PRIMARY KEY (`counter`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

J'ai ensuite créé une fonction php pour qu'à chaque fois insérer un nouvel enregistrement, lire l'identifiant généré et le supprimer immédiatement. Mysql conserve dans son état de compteur de mémoire. Tous les nombres générés sont uniques jusqu'à ce que vous réinitialisiez le compteur mysql ou exécutiez une opération TRUNCATE TABLE

trouver ci-dessous le modèle créé dans Cakephp pour implémenter tous

App::uses('AppModel', 'Model');
/**
 * UniqueCounter Model
 *
 */
class UniqueCounter extends AppModel {

/**
 * Primary key field
 *
 * @var string
 */
    public $primaryKey = 'counter';

/**
 * Validation rules
 *
 * @var array
 */
    public $validate = array(
        'counter' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                //'message' => 'Your custom message here',
                //'allowEmpty' => false,
                //'required' => false,
                //'last' => false, // Stop validation after this rule
                //'on' => 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
    );

    public function get_unique_counter(){
        $data=array();
        $data['UniqueCounter']['counter']=0;
        $data['UniqueCounter']['field']=1;

        if($this->save($data)){
            $new_id=$this->getLastInsertID();
            $this->delete($new_id);
            return($new_id);
        }
        return(-1);
    }
}

Tout contrôle sur l'étendue d'appartenance du résultat peut être implémenté dans la même fonction, en manipulant le résultat obtenu.

1
Granduca

La fonction Rand () générera un nombre aléatoire, mais pas garantira l’unicité. La bonne façon de gérer les identifiants uniques dans MySQL est de les déclarer avec AUTO_INCREMENT .

Par exemple, il n'est pas nécessaire d'indiquer le champ id dans le tableau suivant pour les insertions et il sera toujours incrémenté de 1:

CREATE TABLE animal (
     id INT NOT NULL AUTO_INCREMENT,
     name CHAR(30) NOT NULL,
     PRIMARY KEY (id)
);
0
Kaleb Brasee

Créez un index unique sur le champ dont vous souhaitez le numéro aléatoire unique #

Puis courir

Update IGNORE Table Set RandomUniqueIntegerField=FLOOR(Rand() * 1000000);

0
user3649739

J'ai essayé d'utiliser cette réponse , mais cela n'a pas fonctionné pour moi, j'ai donc dû modifier un peu la requête d'origine.

SELECT FLOOR(1000 + Rand() * 89999) AS random_number
FROM Table
WHERE NOT EXISTS (SELECT ID FROM Table WHERE Table.ID=random_number) LIMIT 1
0
Ankur