Taas (pitkästä aikaa) tulen tänne jakamaan tietokantaongelmiani. Tällä kertaa olen päässyt jo aika "pitkälle", mutta en kuitenkaan onnistunut kaikkea sivuille säätämään yksikseni :(
Nyt ongelmana siis se, että tällä sivulla tulisi tuolla "race record" osiossa tulostaa siihen koontitaulukkoon (iän mukaan jaoiteltu lähdöt ja sijoitukset sekä voittosummat) hevosen iän mukaan kaksivuotiaasta sen ikäiseen kuinka vanha hevonen nyt on. Kilpailut ovat omassa taulussaan ja hevosten tiedot toisessa, ikä löytyy hevostieto-taulusta.
Esimerkiksi, jos hevonen on nyt 5, niin tauluun tulostetaan vain tulokset 2-, 3-, 4- ja 5-vuotiskausilta. Jos hevonen on 8-vuotias tulostetaan tulokset seitsemältä vuodelta.
Alla esimerkki miten olen 2-vuotiskauden tulokset laittanut tulostumaan (ei ole siistiä eikä nättiä, korjausehdotuksiakin voi heittää :D).
// valmistetaan kysely $kysely = $yhteys->prepare("SELECT COUNT(sija) FROM laukkakilpailut WHERE id = '$id' AND ika = '2';"); // suoritetaan kysely $kysely->execute(); // näytetään kyselyn tulokset taulukossa // käsitellään tulostaulun rivit yksi kerrallaan while ($rivi = $kysely->fetch()) { // $rivi["virallinennimi"] sisältää nimen // $rivi["rotu"] sisältää hinnan echo "<td class=\"race2\">" . $rivi["COUNT(sija)"] . "</td>"; } // valmistetaan kysely $kysely = $yhteys->prepare("SELECT COUNT(sija) FROM laukkakilpailut WHERE sija = '1' AND id = '$id' AND ika = '2';"); // suoritetaan kysely $kysely->execute(); // näytetään kyselyn tulokset taulukossa // käsitellään tulostaulun rivit yksi kerrallaan while ($rivi = $kysely->fetch()) { // $rivi["virallinennimi"] sisältää nimen // $rivi["rotu"] sisältää hinnan echo "<td class=\"race3\">" . $rivi["COUNT(sija)"] . "</td>"; } // valmistetaan kysely $kysely = $yhteys->prepare("SELECT COUNT(sija) FROM laukkakilpailut WHERE sija = '2' AND id = '$id' AND ika = '2';"); // suoritetaan kysely $kysely->execute(); // näytetään kyselyn tulokset taulukossa // käsitellään tulostaulun rivit yksi kerrallaan while ($rivi = $kysely->fetch()) { // $rivi["virallinennimi"] sisältää nimen // $rivi["rotu"] sisältää hinnan echo "<td class=\"race3\">" . $rivi["COUNT(sija)"] . "</td>"; } // valmistetaan kysely // valmistetaan kysely $kysely = $yhteys->prepare("SELECT COUNT(sija) FROM laukkakilpailut WHERE sija = '3' AND id = '$id' AND ika = '2';"); // suoritetaan kysely $kysely->execute(); // näytetään kyselyn tulokset taulukossa // käsitellään tulostaulun rivit yksi kerrallaan while ($rivi = $kysely->fetch()) { // $rivi["virallinennimi"] sisältää nimen // $rivi["rotu"] sisältää hinnan echo "<td class=\"race3\">" . $rivi["COUNT(sija)"] ."</td>"; } // valmistetaan kysely $kysely = $yhteys->prepare("SELECT SUM(voittosumma) FROM laukkakilpailut WHERE id = '$id' AND ika = '2';"); // suoritetaan kysely $kysely->execute(); // näytetään kyselyn tulokset taulukossa // käsitellään tulostaulun rivit yksi kerrallaan while ($rivi = $kysely->fetch()) { // $rivi["virallinennimi"] sisältää nimen // $rivi["rotu"] sisältää hinnan echo "<td class=\"race3\">" . $rivi["SUM(voittosumma)"] . "</td></tr>"; }
Tuosta voin sanoa, että ainakin kommentit on huonot. Kommenttien olisi hyvä vastata kysymykseen "mitä ja miksi tehdään" ennemmin kuin "miten tehdään". Se "miten tehdään" yleensä selviää varsinaisesta koodistakin helposti.
Sitten tämäntyyppiset jutut pistää aina itkettämään
lainaus:
// $rivi["rotu"] sisältää hinnan
Olisi kiva jos tietäisi tietokannan skeman, niin olisi helpompi kommentoida.
PDO:n ideana on, että kyselyihin tungettavat muuttujat annettaisiin parametreina. Jos ne työntää tuonne kyselystringin sisään, niin silloin melko tehokkaasti onnistuu poistamaan kaikki hyödyt esimerkiksi injektioiden torjunnan kannalta. Lisäksi kannattaisi tehdä mieluummin yksi kysely joka antaa useamman rivin kuin kopioida yhtä yksittäisen rivin antavaa kyselyä moneen kertaan. Ja jos nyt saman kyselyn ajaminen eri parametreilla olisi jostain syystä perusteltua, niin se kannattaisi tehdä loopissa, eikä copy&pastailla sitä koodia.
Seuraavan pitäisi tehdä mitä haluat. En ole testannut, koska käytössä ei ole sql skemaa enkä todellakaan jaksa alkaa arvailemalla tehdä omaa kopiota tietokannasta.
Kannattaa huomata, että tämä tekee kaiken tarvittavan 2 tietokantakyselyllä. Omalla tyylilläsi olisi tullut 5 kyselyä jokaista ikävuotta kohden, eli esim. 7 vuotiaalle hevoselle 30 kyselyä.
<? //Tulostetaan seuraavan näköistä taulukkoa: //Ikä sijoituksia 1.sijoja 2.sijoja 3.sijoja voittosumma //2 12 5 2 1 27329 //Käytössä on seuraavat muuttujat //$yhteys PDO yhteysolio //$id Hevosen ID-numero //$ika Hevosen ikä ?><tr><th>Ikä</th><th>sijoituksia</th><th>1. sijoja</th><th>2. sijoja</th><th>3. sijoja</th><th>voittosumma</th></tr> <?php //Haetaan sijoitukset ja voittosummat. Haetaan väh 2 vuoden ikäisenä. Ikää ei tarvitse rajoittaa ylhäältä koska hevonen tuskin on kilpaillut ikäänsä vanhempana $kysely = $yhteys->prepare('SELECT ika, COUNT(sija) kpl, SUM(voittosumma) summa FROM laukkakilpailut WHERE id=? AND ika>=2 GROUP BY ika'); $kysely->execute(array($id)); //Kerätään tulokset taulukkoon while ($rivi = $kysely->fetch()) { $sijoituksia[$rivi['ika']] = $rivi['kpl']; $voittosummat[$rivi['ika']] = $rivi['summa']; } //Haetaan eritellyt sijoitukset sijoille 1-3 $kysely = $yhteys->prepare('SELECT ika, sija, COUNT(sija) kpl FROM laukkakilpailut WHERE id=? AND ika>=2 AND sija<4 GROUP BY ika, sija'); $kysely->execute(array($id)); //Kerätään tulokset taulukkoon while ($rivi = $kysely->fetch()) { $sijoja[$rivi['ika']][$rivi['sija']] = $rivi['kpl']; } //Tulostetaan aiemmin taulukkoon kerätyt. Jos iälle ei ole lainkaan sijoituksia, tulostetaan "Ei sijoituksia" for ($vuosi = 2; $vuosi <= $ika; $vuosi++) { echo "<tr><td class=\"race1\">$vuosi</td>"; if (isset($sijoituksia[$vuosi])) { echo '<td class="race2">' . $sijoituksia[$vuosi] . '</td>'; //Näytetään sijataulukon tämän iän sijat 1-3 tai 0 jos arvoa ei ole. for ($i=1; $i<4; $i++) { echo '<td class="race3">' . ( isset($sijoja[$vuosi][$i]) ? $sijoja[$vuosi][$i] : 0 ) . '</td>'; } echo '<td class="race2">' . $voittosummat[$vuosi] . '</td>'; } else { echo '<td class="race2" colspan="5">Ei sijoituksia</td>'; } echo '</tr>'; }
Ainakin omasta mielestäni tuo on paljon kivempi lukea kuin alkuperäinen koodi.
Jos et saa toimimaan, niin laita tietokanta johonkin ladattavaksi niin voin testata itse mikä siinä mättää.
Grez, kiitos tosi paljon! Toi näyttää paljon siistimmältä ja älykkäämmältä ratkasulta kun omani. Ainoo vaan että en saa toimiin kun herjaa erroreita jostain puuttuvista tai ylimääräsistä merkeistä. Miten voin laittaa tietokannan ladattavaksi jonnekin :D?
Korjasin virheet aikaisemmasta koodista. (eipä tuossa nyt niin paljon tietokantaa ole ettenkö voisi itsekin kokeilla virittää pystyyn ja testata. )
Yleisesti ottaen erilaisissa hallintatyökaluissa on "backup database" tai "database dump" tyylinen toiminto. Tietokannan varmuuskopiointi on muutenkin hyvä idea ja itse teen sitä säännöllisen varmuuskopiointikäytännön (joka saattaa olla ostettu palvelu, jolloin siitä ei tarvitse itse huolehtia) lisäksi mm. ennen isompia muutoksia.
Tosin ei tuo koodikaan niin monimutkainen ole, ettetkö olisi siitä itsekin voinut selvittää nuo virheet..
Kiitos tosi paljon. Surffailen nyt kännykällä joten en pääse testaan. Kiitti myös tosta varmuuskopiointi vinkistä. Pitänee ottaa kopiot ulkoselle heti huomenissa :)!
Äh, ei toi toimi vieläkään, se ei tulosta mitään eikä edes herjaa mitään? Heitin sen tänne ihan sivun alareunaan progenyn alle.
muoks// huomasin justiinsa että oon hieman sekavasti selittäny ton ikäsysteemin. Laukkakilpailut taulussa joka rivillä on "ika" joka kertoo kuinka vanhana kilpailu on käyty ja hevoset taulussa on hevosen nykyinen ikä "ika" kohdassa.
No mitä sulla on noissa muuttujissa $ika ja $id?
Mulla toimi ihan ok ja juuri tuollaisella tietokannalla kuin äsken kuvailit.
Ää, oon ihan hukassa. Mihissä kohtaa mun pitäis määritellä ikä- ja id-muuttujat? Kun eikös tuonne vaan pidä id=? kohtaan korjata se id=$id (mulla ylhäällä määritetty id osotteen mukaan - tolla tyylillä haen tiedot muissakin kohdissa), mutta miten ja minne ikä?
Siis eihän tuonne tarvitse muuta kuin lisätä alkuun
<? $id = 73; $ika = 5; ?>
Tai miten vaan / jotkut järkevät arvot. Oletan että haet niitä tietoja jostain tuossa aikaisemmin, omassakaan koodissasi ei näkynyt missä $id määritellään.
Oletan, että tarkoitit seuraavaa: urli.com/heppasivu/kivaheppa.php?id=123&ika=12. Saat poimittua nuo tiedot helposti tähän tapaan.
<?php $id = $_GET['id']; $ika = $_GET['ika']; ?>
EDIT:
Äh, unohda tuo ikä tuosta kokonaan. Grez ylempänä jo mainitsikin, että sinun täytyy se id hakea jostain muualta.
Esim. hepat.php tulostaa kaikki hepat ja linkit heidän sivuilleen tyyliin:
<?php # Hae nämä tietokannasta $hepat = array(1 => "heppa 1", 2 => "heppa 2", 3 => "heppa 3", 4 => "heppa 4"); foreach($hepat as $heppaid => $heppanimi){ echo '<a href="heppa.php?id=' . $heppaid . '">' . $heppanimi . '</a>'; } ?>
EDIT2: Typokin vielä.
EDIT3: Intouduin väsäämään nopean esimerkin, joka ainakin äkkiseltään vaikuttaa toimivan. Kannattaa kuitenkin suhtautua annettuun esimerkkiin kriittisesti.
<?php #hepat.php $hepat = array(1 => "heppa 1", 2 => "heppa 2", 3 => "heppa 3", 4 => "heppa 4"); ?>
<?php #listaahepat.php # Hae nämä tietokannasta include_once("hepat.php"); foreach($hepat as $heppaid => $heppanimi){ echo '<a href="heppa.php?id=' . $heppaid . '">' . $heppanimi . '</a><br />'; } ?>
<?php #heppa.php include_once("hepat.php"); if(isset($_GET['id'])){ $id = $_GET['id']; if(array_key_exists($id, $hepat)){ echo 'Hei! Minun nimeni on: ' . $hepat[$id]; }else{ echo 'Hakemaasi heppaa ei löytynyt!'; } }else{ echo 'VIRHE! Palaa etusivulle <a href="index.php">tästä!</a>'; } ?>
Siis kun mulla on id tolla sun ekalla esimerkillä (get), mutta pohdin että miten saada ikä workkin. Kun sitä ei voi laittaa getillä, koska urlin tulee olla sama koko ajan (muut ihmiset linkittävät hevosiani sivuilleen niin toi ikä siellä lopussa ei käy). Yritin hakee $ika:lle tulosta taulusta hevoset, mutta se ei toiminut :(
Siis ideahan oli laittaa esimerkki, josta voit jatkaa itse eteenpäin. Ei tuosta pitäisi olla hirveän vaikea kokeilla laittaa vaikka $ika = 15; ja katsoa mitä tapahtuu ja siitä sitten jatkokehittää.
Oletin että joka tapauksessa luet tietokannasta jotain hevosen tietoja (nimi yms) niin ikä kannattaisi lukea siinä samalla. Mutta toki sen taulukon voisi tulostaa niinkin, että jättää ikärajoituksen kokonaan pois ja poimii suurimman iän mikä ko. hevoselle löytyy laukkakilpailut taulusta. Tästä menisi se minuutti kirjoittaa esimerkki, mutta taidan jättää itse pureskeltavaksi.
Nokun ongelma on se, etten ole mikään pro ja kaikki koodit on jostain oppaista yms. eli ei itsetuotettua. Laitan nyt tähän alle, miten mm. idin haen ja miten luulin hakevani iän.
<?php $id = $_GET ['id']; $idt = array ("0001", "0002", "0003", "0004", "0005", "0006", "0007"); if (!in_array ($id, $idt)) $id = "0001"; // virheenkäsittely: virheet aiheuttavat poikkeuksen $yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //Haetaan sijoitukset ja voittosummat. Haetaan väh 2 vuoden ikäisenä. Ikää ei tarvitse rajoittaa ylhäältä koska hevonen tuskin on kilpaillut ikäänsä vanhempana $kysely = $yhteys->prepare("SELECT ika FROM hevoset WHERE id = '$id'"); $kysely->execute(); //Kerätään tulokset taulukkoon while ($rivi = $kysely->fetch()) { $ika = $rivi['ika']; } //Haetaan sijoitukset ja voittosummat. Haetaan väh 2 vuoden ikäisenä. Ikää ei tarvitse rajoittaa ylhäältä koska hevonen tuskin on kilpaillut ikäänsä vanhempana $kysely = $yhteys->prepare("SELECT ika COUNT(sija) kpl, SUM(voittosumma) summa FROM kilpailut WHERE id = '$id' AND ika>=2 GROUP BY ika"); $kysely->execute(array($id)); //Kerätään tulokset taulukkoon while ($rivi = $kysely->fetch()) { $sijoituksia[$rivi['ika']] = $rivi['kpl']; $voittosummat[$rivi['ika']] = $rivi['summa']; } //Haetaan eritellyt sijoitukset sijoille 1-3 $kysely = $yhteys->prepare("SELECT ika, sija, COUNT(sija) kpl FROM kilpailut WHERE id= '$id' AND ika>=2 AND sija<4 GROUP BY ika, sija"); $kysely->execute(array($id)); //Kerätään tulokset taulukkoon while ($rivi = $kysely->fetch()) { $sijoja[$rivi['ika']][$rivi['sija']] = $rivi['kpl']; } //Tulostetaan aiemmin taulukkoon kerätyt. Jos iälle ei ole lainkaan sijoituksia, tulostetaan "Ei sijoituksia" for ($vuosi = 2; $vuosi <= $ika; $vuosi++) { echo "<tr><td class=\"race1\">$vuosi</td>"; if (isset($sijoituksia[$vuosi])) { echo '<td class="race2">' . $sijoituksia[$vuosi] . '</td>'; //Näytetään sijataulukon tämän iän sijat 1-3 tai 0 jos arvoa ei ole. for ($i=1; $i<4; $i++) { echo '<td class="race3">' . ( isset($sijoja[$vuosi][$i]) ? $sijoja[$vuosi][$i] : 0 ) . '</td>'; } echo '<td class="race2">' . $voittosummat[$vuosi] . '</td>'; } else { echo '<td class="race2" colspan="5">Ei sijoituksia</td>'; } echo '</tr>'; }?>
Ihan päin prinkkalaa tämä, alkaa tympiin kun en tajua tätä yhtään x)
Jos id-kenttä on auto increment, niin id:ssä ei kuulu olla nollia.
Lisäksi muuta nuo kyselyt siten, että et laita varsinaiseen kyselyyn muuttujia, vaan pistät ne execute-funktioon.
Esim.
$kysely = $yhteys->prepare("SELECT ika FROM hevoset WHERE id = '$id'"); $kysely->execute();
->
$kysely = $yhteys->prepare("SELECT ika FROM hevoset WHERE id = ?"); $kysely->execute(array($id));
Kannattaa myös ottaa tunnukset pois koodista.
Oho, olinpas huolimaton ton sisäänkirjautumis kohdan kanssa :D Ja kiitos, korjasin noi sun näyttämät virheet :)!
Aihe on jo aika vanha, joten et voi enää vastata siihen.