webForumDet fria alternativet

Fisketävling-hur skriva sql-koden?

6 svar · 272 visningar · startad av crisscross

crisscrossMedlem sedan feb. 20044 inlägg
#1

Ska göra en fisketävling för en fiskeklubb.
Tävlingen går ut på att få så stora fiskar som möjligt av olika arter, sedan skall poäng räknas efter ett visst system:

I varje art får de 15 största fiskarna poäng från 15 för den största ned till 1 för den 15:e. Bara medlemmens 5 största fiskar i den aktuella arten ger poäng. Fiskar med samma vikt delar på poängen för de placeringarna ( Om t.ex. de två största fiskarna väger lika mycket får de (15+14)/2=14,5 poäng). Det kan bli mer än 15 fiskar som får poäng om plats 15 delas av flera fiskar, de får då dela på 1 poäng.

Tabellen består av:

Id
Namn
Art
Vikt
Poäng

Jag har med hjälp av ett webbformulär och PHP fått till det så att fiskar kan matas in via webben, problemet kommer när jag ska beräkna poängen för varje Id. Först måste man ju jämföra med medlemmens anmälda fiskar av den arten. Platsar den inte bland medlemmens 5 största fiskar blir ju poängen noll.
Platsar den så måste man ju jämföra med alla Id av den arten och uppdatera poängen för alla Id av den arten om den går in bland de 15 största.

Jag är helt färsk på programmering, databaser och framförallt SQL/PHP så om någon kan hjälpa mig i rätt riktning så skulle jag bli lycklig!

LarsGMedlem sedan dec. 200012 464 inlägg
#2

Vilken databashanterare använder du? Om man vill lösa allt i SQL så blir det ganska komplicerat och det är inte säkert att det ens går att lösa (beroende på begränsningar i aktuell DBMS.)

crisscrossMedlem sedan feb. 20044 inlägg
#3

Här kom svaren snabbt!
Jag använder mySQL-admin. Kanske det skulle vara smidigare att på något sätt lösa det med PHP för att uppdatera databasen varje gång någon har matat in data i databasen?
Som sagt jag är helt färsk på det här med databaser så jag har inte en aning om hur jag ska lösa det.

crisscrossMedlem sedan feb. 20044 inlägg
#4

Förlåt. phpMyAdmin (2.5.4) heter den ju. En webb-baserad variant som mitt webbhotell tillhandahåller. MySQL 3.23.58 är databasen.

LarsGMedlem sedan dec. 200012 464 inlägg
#5

Okej, då det är Mysql så kan vi utesluta en helt SQL-baserad lösning (en sådan är att föredra av prestandaskäl).

Några påpekanden

Jag skulle använda två tabeller

persons

name
total -- totalpoäng

catches

name
art
weight
points

Jag skulle inte döpa en kolumn till poäng (åäö ställer bara till problem.)

$art etc hänvisar till de värden som du hämtar från den första select-satsen.

//För varje post      
  
// select * from catches

   while ( $row = mysql_fetch_row($q) ) {

//     Hämta hur många som har en fisk 
//    som är större i samma art 

// select count(*) from catches where Art = '$art'
//              and $name /= $name and weight > $weight )
//
//  $c1 innehåller antalet

       if ( $c1  > 15 ) $point = 0;
       else {

//   Hämta hur många som har en fisk som 
//   är lika i samma art

//   select count(*) from catches 
//     where Art = '$art'
//         and name /= $name 
//        and weight = $vikt ) 
//
// $c2 innehåller antalet

             $point = 15 - $c1;
             if ( $points <= 0 ) $point = 1;  
             if  $c1 +  $c2 <= 15 $point += $c2*0.5;
        }
// uppdatera

//  update catches set point = $point 
// where art = $art and name = $name
    }
// Alla poster uppdaterade

//hämta alla poster och räkna samman poäng

// select * from catches where point > 0
//   order by name,point desc

    $name = '';
    $totalp = 0;
    $c = 0;
    while ( $row = mysql_fetch_row($q)) {
        if ( $name != $row["namn"] ) {
            if  ( !$totalp ) {
// update persons set total = $totalp 
// where name = $name
            }
           $totalp = 0;
           $c = 0;  
        }
      if  ( $c < 5 ) {
         $totalp += $row(["points"]);
         $c++;
     }
  }
   if  ( !$totalp ) {
// update persons set total = $totalp 
// where name = $name
            }
// hämta list med rangordning
//
//  select name,total from persons order by total desc

Nu saknas all kod för att utföra själva SQL-satserna och hämtar data till variabler men det finns ett flertal exempel på hur man gör det i PHP-manualen.

HakanSMedlem sedan dec. 2002529 inlägg
#6

Jag skulle göra en tabell med följande:

Fiskare
Art
Vikt

Poängen beräknas och visas då någon vill se dem. På så sätt behöver inte alla poster i databasen uppdateras när någon lägger in en fångstanmälan.

crisscrossMedlem sedan feb. 20044 inlägg
#7

Tack för all hjälp!
Jag funderar vad som egentligen är bäst att göra, fick den här lösningen i ett annat forum (precis som HakanS föreslår så räknar den ut poängen när någon frågar efter den):

<?php
    define("FISKAR_PER_ART_O_FISKARE", 5);
    define("FISKAR_PER_ART", 15);    
    
    $start = microtime();
    error_reporting(E_ALL);
    ini_set("display_errors", "1");
    $link = mysql_connect ("xxx.com", "xxx", "xxx");
    mysql_select_db("xxx", $link);
 
    $arter = array();
    $fiskare = array();
    $query = "SELECT * 
              FROM interna
              ORDER BY
              art, vikt DESC";
    $result = mysql_query($query, $link);
 
    while($f = mysql_fetch_array($result,MYSQL_ASSOC)) {
        $art = $f['art'];
        $namn = $f['namn'];
        if (!isset($fiskare[$namn][$art]['nof'])) {
            $fiskare[$namn][$art]['nof']=0;
        }
        $fiskare[$namn][$art]['nof']++;
        if ($fiskare[$namn][$art]['nof'] <= FISKAR_PER_ART_O_FISKARE) {
            $arter[$art][] = array('namn' => $f['namn'], 
                                   'vikt'      => $f['vikt']
                                  );
        }
    }
 
    reset($arter);
    $next=current($arter);
    while ($next) {
        $curr_art = key($arter);
        $pos=0;
        $shared_points=0;
        while (isset($arter[$curr_art][$pos]) && $pos < FISKAR_PER_ART) {
            while ((isset($arter[$curr_art][$pos+$shared_points+1]['vikt'])) && ($arter[$curr_art][$pos]['vikt'] == $arter[$curr_art][$pos+$shared_points+1]['vikt'])) {
                $shared_points++;
            }
            $points=$points=FISKAR_PER_ART-$pos-0.5*$shared_points;
            $curr_pos=$pos;
            while ($pos <= ($curr_pos+$shared_points)) {
                $arter[$curr_art][$pos]['points']=$points;
                $pos++;
            }
            $shared_points=0;
        }
        $next = next($arter);
    }
    
    va($arter);
    print(microtime()-$start);
 
    function va(& $arr) {
        print("<pre>");
        print_r($arr);
        print("</pre>");
    }
?>
136 ms totalt · 3 externa anrop · v20260731065814-full.fb544a5a
130 ms — hämta forumlista (db)
0 ms — hämta statistik (cache)
134 ms — hämta tråd, inlägg och bilagor (db)