2010-03-30 4 views
3

J'ai une table qui décrit une variété d'objets dans mon système (par exemple, parapluie, bottes, sacoche, peu importe). Chacun de ces objets doit avoir une prévalence ou une incidence distincte. Par exemple, le parapluie est plus rare que les bottes. Sur la base de ces facteurs, j'ai besoin de sélectionner au hasard un objet unique (y compris un blanc ou «aucun objet trouvé») basé sur cette valeur d'incidence.Sélectionnez une ligne aléatoire dans la table, mais avec des cotes?

Yikes. Avoir du sens?

+0

Quelle devrait être la probabilité de ne sélectionner aucun objet? Est-ce stocké dans la base de données ou est-ce une constante codée en dur? –

+0

Probable comme marque constante. – Don

Répondre

0

Je vais modifier la réponse de symcbean pour cela, +1 pour symcbean.

SELECT * FROM some_table 
WHERE (100*RAND()) < some_table.percent_probability

Cela renverra TOUS les résultats correspondant à la probabilité que vous souhaitez intuitivement leur attribuer. Par exemple, 5 objets avec une probabilité de 20 seront tous retournés 20% du temps. Les objets d'une valeur de 90 seront retournés 90% du temps.

Ainsi, votre résultat sera plus d'un objet, mais vous avez empêché les rares d'apparaître aussi souvent. Alors maintenant, saisissez un de vos résultats au hasard. Un moyen facile serait de les coller tous dans un tableau et:

$items = array(); // assuming you've already filled $items with your 
        // query results, one item for each array key 

$count = count($items); 

$chosen_key = rand(1,$count)-1; 

$chosen_item = $items[$chosen_key];
+0

Un grand merci: J'essaie cela rapidement, et ça a l'air bien, mais je reçois une erreur de décalage quand un seul résultat est retourné? "Message: Offset non défini: 1" – Don

+0

Me = muet. Je l'ai. La fonction rand() commençait à 1 et manquait donc la première clé à [0]. – Don

+0

Modifié pour corriger l'erreur de décalage non définie. Merci d'avoir fait remarquer cela. –

1
SELECT * FROM some_table 
WHERE (100*RAND()) > some_table.percent_probability 
LIMIT 1 

.... et la probabilité de sélection est stockée dans le champ percent_probability.

C.

+0

Cela semble réalisable, mais trompeur. Par exemple si vous avez 5 objets, chacun avec un 20 comme pour cent_probability (pensant que chacun devrait apparaître 20% du temps) alors un élément sera retourné 80% du temps, rien ne sera retourné 20% du temps, et les 4 autres articles ne seront jamais retournés. Vous devez donner aux items une probabilité de 0, 20, 40, 60 et 80 pour que chacun ait une chance égale. –

+0

@Syntax Erreur: oui vous avez partiellement raison - à la réflexion les maths sont un peu plus complexes que vous ne le suggérez, mais facilement fixés en faisant un ordre aléatoire et en déplaçant le filtre d'où (avant le tri) vers une clause having (c'est-à-dire après). – symcbean

1

Si vous avez un scénario d'écriture rarement en lecture beaucoup (vous changer les objets et les probabilités rarement), vous voudrez peut-être pré calculer les valeurs de probabilité de sorte que si vous avez une seule valeur aléatoire, vous pouvez décider sans ambiguïté quel objet choisir (avec un seul choix, aucun tri, aucune comparaison de tous les enregistrements nécessaires).

E.g. (Probabilités par moulin)
parapluie: 500 ‰ hasard
bottes: 250 ‰ hasard
Cartable: 100 ‰ hasard
tout: 100 ‰ hasard
"rien": 50 ‰ hasard

Un hasard nombre entre 0 et 499 signifie "parapluie" a été choisi, 500-749 "bottes" et ainsi de suite.

INSERT INTO foo (name, randmin, randmax) VALUES 
    ('umbrella', 0, 499), 
    ('boots', 500, 749), 
    ('satchel', 750, 849), 
    ('whatever', 850, 949) 

Chaque fois que vous ajoutez un objet ou modifiez les probabilités, recréez ce tableau.

Ensuite, tout ce dont vous avez besoin est une requête comme

SELECT 
    f.name 
FROM 
    ( 
    SELECT Round(Rand()*1000) as r  
) as tmp 
JOIN 
    foo as f 
ON 
    r BETWEEN f.randmin and f.randmax 
LIMIT 
    1 

Une seule valeur aléatoire doit être généré et MySQL peut utiliser un index sur (randmin, randmax) pour trouver l'enregistrement rapidement.

Questions connexes