Willekeurige prijzen uitkeren aan gebruikers

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Marco Eilander

Marco Eilander

15/05/2013 23:42:56
Quote Anchor link
Hallo,

Ik ben bezig met het maken van een online loterij, wat bedoelt is als kleine
event / activiteit. Nu lukt het mij niet om willekeurige prijzen uit te keren aan gebruikers.

Ik deed het zo, ik kon geen andere manier bedenken dan deze:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?php

$sql
= (mysql_query("SELECT * FROM loteryprijzen ORDER BY rand()"));

while($row = mysql_fetch_assoc($sql)) {
    mysql_query("UPDATE `lotery` SET `icon`='".$row['icon']."', `price`='".$row['itemname']."'");
    
}


?>


Je zult vast het probleem al zien, namelijk, er word 1 random prijs gekozen, en die word aan alle deelnemers gegeven.

De bedoeling is, als er bijvoorbeeld 5 deelnemers zijn, dat de prijzen random worden verdeeld :

Winnaar 1 wint : 50 munten
Winnaar 2 wint : 30 munten
winnaar 3 wint : een gelukskoekje
" "
" "

Wanneer de loterij is afgelopen, gebruik ik het zelfde methode, om 5 winnaars te selecteren.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$sql = mysql_query("SELECT * FROM lotery ORDER BY user_id,rand() LIMIT 5");


Weet iemand een betere / goede manier?

Alvast bedankt.

Groeten,
Marco
Gewijzigd op 15/05/2013 23:45:00 door Marco Eilander
 
PHP hulp

PHP hulp

25/04/2024 12:39:00
 
Kevin Driessen

Kevin Driessen

16/05/2013 11:58:19
Quote Anchor link
Goh, na toch redelijk wat met mysql te maken gehad te hebben was 'order by rand()' mij nog onbekend. Uit de eerste zoekresultaten zie ik echter meteen al dingen als 'vermijd het gebruik hiervan'. Het schijnt niet echt goed te zijn voor de performance: http://www.webtrenches.com/post.cfm/avoid-rand-in-mysql

Als in jouw database tabel slechts vijf rijen zijn en dit ook zo blijft, dan zal je code denk ik prima zijn. Zou je echter duizend deelnemers hebben, dan gaat die rand() functie flink aan de performance vreten.


Dan even wat verder gezocht: http://www.rndblog.com/how-to-select-random-rows-in-mysql/
Betere code lijkt dan het volgende resultaat te krijgen:

SELECT * FROM lotery WHERE RAND()<=[aantal winnaars/totaal aantal rijen] limit [aantal winnaars];

Nogmaals: voor een tabel met slechts 5 rijen zal dit verschil onmerkbaar zijn, maar 't is wel iets om in gedachte te houden.
 
Marco Eilander

Marco Eilander

16/05/2013 12:09:36
Quote Anchor link
@kevin, er kunnen maximaal 50 deelnemers mee doen. Is het dan nog steeds handig om de rand() op mijn manier te gebruiken?

Alvast bedankt! :)

Nu is dat stukje voor mij bekent, al zit ik nog wel met het probleem bij het uitkeren van de prijzen.
Ook dat gaat willekeurig, maar wil wel hebben dat ze daadwerkelijk verschillende prijzen krijgen en niet allemaal het zelfde, zoals het te zien is in mijn voorbeeld.
 
Kevin Driessen

Kevin Driessen

16/05/2013 12:40:40
Quote Anchor link
Quote:
er kunnen maximaal 50 deelnemers mee doen. Is het dan nog steeds handig om de rand() op mijn manier te gebruiken?
Ik ben er de expert niet naar om dit te beantwoorden, maar in de eerste link die ik gaf, werd gezegd dat het meer dan een seconde duurde om ruim 5000 rijen op die manier te verwerken. Te verwachten is dat 50 rijen weinig voorstelt en dus nog steeds niet echt merkbaar is.

Het is echter nooit slecht om een betere aanpak te verkiezen. Stel dus dat je een onbekend aantal deelnemers hebt en hiervan 5 wil selecteren, dan denk ik dat je de volgende code zou kunnen gebruiken:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
SELECT * FROM lotery WHERE RAND()<=5/(select count(1) from lotery) limit 5



Quote:
maar wil wel hebben dat ze daadwerkelijk verschillende prijzen krijgen en niet allemaal het zelfde, zoals het te zien is in mijn voorbeeld.

Als ik jouw code goed begrijp, dan selecteer jij eerst 5 willekeurige rijen uit loteryprijzen. Vervolgens doorloop je deze rijen en bij iedere rij update je alle rijen in lotery. Het effect is vanzelfsprekend: de laatste rij zorgt ervoor dat iedereen in lotery dezelfde prijs heeft (ook de niet-winnaars).
Selecteer je daarna dus 5 winnaars, dan hebben deze vanzelfsprekend dezelfde prijs.

Misschien is het een beter idee om eerst 5 winnaars te selecteren. Vervolgens doorloop je de rijen van deze winnaars en kies je een willekeurige prijs uit. Waar je dan nog voor moet zorgen is dat je geen prijs selecteert die je al had geselecteerd (tenzij het toegestaan is dat dezelfde prijs bij toeval wordt uitgekeerd).

Toevoeging op 16/05/2013 12:46:12:

Ik denk dat de code er ongeveer zo komt uit te zien, uitgaande dat het toegestaan is dezelfde prijs bij toeval uit te keren:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?php
mysql_query("
  UPDATE lotery
  SET icon = price_icon, price = price_itemname
  FROM (
    SELECT icon AS price_icon, itemname AS price_itemname
    FROM loteryprijzen
    WHERE RAND()<=1/(select count(1) from loteryprijzen) limit 1
  )
  WHERE RAND()<=5/(select count(1) from lotery) limit 5
"
);
?>
Gewijzigd op 16/05/2013 12:47:14 door Kevin Driessen
 
Marco Eilander

Marco Eilander

16/05/2013 13:51:16
Quote Anchor link
Uhm, op één of ander manier, gebeurt er niks met de code.
Ik krijg geen errors, dus dat probleem is het niet. Er word niks gewijzigd.
 
Kevin Driessen

Kevin Driessen

18/05/2013 02:38:25
Quote Anchor link
Excuus voor late reactie en de wat minder correcte code. Er mankeert achteraf gezien nogal wat aan die SQL-code. Zo klopt de syntax niet en is het uberhaupt niet mogelijk een in een update-statement een subquery toe te passen op dezelfde tabel.

Als er trouwens iets mis gaat in enkel sql dan krijg je dat niet standaard te zien in php. Om wel een melding te krijgen, kun je bij dit soort dingen gebruik maken van 'OR DIE(mysql_error())', dus als volgt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
mysql_query("<hier je sql logica>") or die(mysql_error());
?>



In een poging mijn wandaden recht te zetten, hier nieuwe code

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
    $sql
= mysql_query("
        SELECT * FROM lotery
        WHERE RAND()<=5/(select count(1) from lotery)
        LIMIT 5
    "
) or die(mysql_error());
    while($row = mysql_fetch_assoc($sql)) {
        mysql_query("
            UPDATE lotery L
                CROSS JOIN(
                    SELECT icon, itemname
                    FROM loteryprijzen
                    WHERE RAND()<=1/(select count(1) from loteryprijzen)
                    LIMIT 1
                ) AS P
            SET L.icon = P.icon, L.price = P.itemname
            WHERE name = '"
.mysql_real_escape_string($row['name'])."'
        "
) or die(mysql_error());
    }

?>


Helaas heb ik niet even snel iets kunnen bedenken om dit elegant met één SQL-query af te handelen, maar bovenstaande code zal de klus denk ik wel klaren.

In jouw voorbeeld/beschrijving komt geen primaire of unieke sleutel naar voren als het gaat om de deelnemers in de tabel lotery. Ik ben voor het gemak maar even uitgegaan van een unieke naam. Als je hier iets anders hebt, zoals 'id', dan kun je naam daarmee vervangen natuurlijk.

Kort toegelicht wat bovenstaande code doet:
- Er worden eerst 5 willekeurige winnaars geselecteerd.
- Iedere rij van deze winnaars wordt doorlopen in php.
- Bij het doorlopen wordt de winnaar ge-update, waarbij één willekeurige prijs geselecteerd wordt.
Gewijzigd op 18/05/2013 02:39:12 door Kevin Driessen
 
Ger van Steenderen
Tutorial mod

Ger van Steenderen

18/05/2013 08:56:27
Quote Anchor link
Kevin Driessen op 16/05/2013 12:40:40:
Het is echter nooit slecht om een betere aanpak te verkiezen. Stel dus dat je een onbekend aantal deelnemers hebt en hiervan 5 wil selecteren, dan denk ik dat je de volgende code zou kunnen gebruiken:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
SELECT * FROM lotery WHERE RAND()<=5/(select count(1) from lotery) limit 5

Ik kan dit geen betere aanpak noemen, want de kans is aanwezig dat er geen 5 records geselecteerd worden.

Buiten dat vraag ik me af of dit werkelijk verschil maakt in performance, deze manier heeft ook een full table scan tot gevolg.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.