Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Tietokannan kanssa tulostusongelmia

Sivun loppuun

merlin [20.07.2011 23:20:32]

#

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>";
}

Grez [21.07.2011 15:06:51]

#

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ää.

merlin [21.07.2011 20:07:50]

#

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?

Grez [21.07.2011 20:42:41]

#

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..

merlin [21.07.2011 22:08:58]

#

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 :)!

merlin [22.07.2011 11:25:11]

#

Ä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.

Grez [22.07.2011 16:17:33]

#

No mitä sulla on noissa muuttujissa $ika ja $id?

Mulla toimi ihan ok ja juuri tuollaisella tietokannalla kuin äsken kuvailit.

merlin [22.07.2011 18:05:59]

#

Ää, 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ä?

Grez [22.07.2011 18:09:19]

#

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.

jimi-kimi [22.07.2011 20:16:54]

#

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>';
}
?>

merlin [22.07.2011 22:30:03]

#

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 :(

Grez [24.07.2011 12:53:46]

#

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.

merlin [24.07.2011 20:58:21]

#

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)

Macro [24.07.2011 21:10:35]

#

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.

merlin [24.07.2011 21:26:57]

#

Oho, olinpas huolimaton ton sisäänkirjautumis kohdan kanssa :D Ja kiitos, korjasin noi sun näyttämät virheet :)!


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta