[MySQL] Zufall - verschiedene Wahrscheinlichkeiten

WhiZZler

Chancentod²
ID: 85586
L
6 Mai 2006
588
32
begrüße

es soll bei einem script zufällig ein gewinner aus der datenbank gelesen werden.. allerdings soll es unterschiedliche wahrscheinlichkeiten geben.. jeder user hat eine gewisse anzahl an punkten.. je mehr punkte der user hat, desto wahrscheinlicher ist es, dass er als gewinner gezogen wird..

wie lässt sich sowas realisieren?

ich habe es zuerst mit folgendem query versucht
Code:
SELECT nick
FROM `lo_users`
ORDER BY RAND( UNIX_TIMESTAMP( ) * UNIX_TIMESTAMP( ) ) , points
aber das funktioniert ja logischerweise nicht, da order by rand eine eindeutige reihenfolge liefert und das "points" beim order befehl somit ignoriert wird..

die einfachste möglichkeit wäre es wohl, das ganze in nen array zu packen und pro punkt nen eintrag in dem array zu machen.. aber das is nich wirklich praktisch, da die punkte zum fast immer 4, manchmal sogar 5 stellig sind..

danke im vorraus
mfg whizzler
 
Da ich annehme, dass du nur höchstens einmal am Tag den Gewinner bestimmst, kannst du ja ein Select sum(punkte) machen und dann mit php einen Zufallswert von 1 bis zu dieser Summe machen. Danach ein über alle Tabellen und die einzelnen Punkte solange summieren bis dieser Zufallswert überschritten wird (an dieser Stelle ist dann der Gewinner).

MfG respawner
 
respawner schrieb:
Da ich annehme, dass du nur höchstens einmal am Tag den Gewinner bestimmst, kannst du ja ein Select sum(punkte) machen und dann mit php einen Zufallswert von 1 bis zu dieser Summe machen. Danach ein über alle Tabellen und die einzelnen Punkte solange summieren bis dieser Zufallswert überschritten wird (an dieser Stelle ist dann der Gewinner).

MfG respawner

Huhu,
das war auch meine erste Idee. Aber wie brichst du beim zweiten Summieren der Punkte an der Stelle der Zufallszahl ab? (ohne stored procedures o.ä.)

Gruß, Zera
 
deswegen meinte ich ja auch ein select über alle Elemente.

PHP:
$sql = mysql_query('select sum(Punkte) from tabelle');
if($max = mysql_fetch_row($sql)) {
  $zufall = mt_rand(1, $max[0]);
  $akt = 0;
  $gesuchte_ID = '';
  $sql2 = mysql_query('select Id, Punkte from tabelle');
  while($row2 = mysql_fetch_row($sql2)) {
    $akt += $row2[1];
    if($akt >= $zufall) {
      $gesuchte_ID = $row2[0];
      break;
    }
  }
  if(!empty($gesuchte_ID)) echo "Der User mit der ID $gesuchte_ID hat gewonnen";
} else {echo "Tabelle leer";}

MfG respawner
 
zerafin schrieb:
Ah schick! Ok klar, in php gehts. :)

Gruß, Zera
Meinte halt, dass man es sowieso nur einmal am Tag machen muss oder wie oft die Verlosung sein soll, dann kann das auch mal ein bisschen länger dauern. Wobei man bei einer einer reinen sql-query wohl ein subselect brauchen würde, was auch nicht unbedingt schnell ist. Wobei ich auch nicht auf die schnelle drauf kommen würde wie das geht (wohl das Problem was du angesprochen hast).

MfG respawner
 
Mit 'nem Subselect und Benutzervariablen könnte man das Ganze etwas verkürzen:
Code:
SET @punkte :=0;

SELECT punkte, id
FROM (
  SELECT @punkte := @punkte + punkte AS punkte, id
  FROM table
  ORDER BY punkte ASC
) AS tempPunkte
WHERE punkte >= randomWert
ORDER BY punkte ASC
LIMIT 0 , 1
[edit]

Zumindest den inneren Teil...
 
Zuletzt bearbeitet:
habe die vorantworten nicht gelesen, aber man könnte für jede 10 punkte 1 los in die Auslosung schmeißen, somit ist eine andere wahrscheinlichkeit gegeben ;-)

Je mehr Punkte, desto mehr Lose in der Auslosung und desto größer die Chance gezogen zuwerden!

hab sowas auch irgendwo rumfliegen, meld dich mal!
 
ZeroCCC schrieb:
wieso nicht einfach
PHP:
ORDER BY 
     RAND()*points
Beispiel warum das nicht passt.
Man hat 2 Werte einmal 1 und 2 also was 1/3 und 2/3 als Chancen ergeben soll.
aber wenn du Rand()*1 > rand()*2 hast dann hast du eine Wahrscheinlichkeit von integeral 1/2*x dx von 0 bis 1 = 1/4 statt 1/3. (Das Einheitsquadrat genommen, dann die Grenze 1. Faktor / 2. Faktor als Gerade und die einzelnen Flächen sind dann die Wahrscheinlichkeiten). Also hätte bei deiner Berechnungsmethode der mit 2 Punkten eine 3mal so hohe Chance wie der mit einem Punkt.

MfG respawner
 
danke für die antworten. aber irgendwie versteh ich nich so recht, warum bzw wie diese methode für mein problem hilft.. wäre für ne kurze erklärung noch sehr dankbar.. ich mach ungern sachen, die ich nicht verstehe ;)
 
Bei meiner Methode werden alle Werte in eine uniforme Verteilung gesteckt.
also als Beispiel
ID Punkte
1 140
2 234
3 343
6 3434
2 443 (es ist egal ob man jetzt z.B. die Punkte hinzufügt per insert oder durch einen update den alten durch den neunen ersetzt)

hier wäre die Summe der Punkte 4594. Man kann es sich so vorstellen, dass man die Punkte als Strecken auf einer Zahlengerade aneinander gehängt werden (umso mehr Punkte einer hat umso länger ist seine Strecke also umso wahrscheinlicher ist, dass er gezogen wird).
Man wählt nun einen zufälligen Wert zwischen 1 und 4594. Jetzt muss man gucken welche Strecke getroffen wurde. Dafür geht man wieder die einzelnen Teilstrecke durch (addiert sie) bis man den zufälligen Wert erreicht hat.
Der Effekt ist der gleiche als würdest du für jeden einzelnen Punkt einen eigenen Datensatz nehmen und es nach rand sortieren lassen und den ersten auswählen, nur halt schneller und weniger Speicherinensiv.

MfG respawner