Olen tässä viimeaikoina räpeltänyt arvosteluskriptiä Ajaxilla ja MySQL:llä. Siinä käyttäjä antaa äänen 1-5. Ajax-puoli toimii täysin moitteettomasti, mutta tietojen lähettäminen on ollut pieni ongelma MySQL:n kanssa.
Käyttäjän napsauttaessa tähteä, Ajaxilla tehdään pyyntö tiedostoon aani.php
, jolloin tietojen tulisi tallentua tietokantaan. Eipä näin kuitenkaan käynyt. $jakso
ja $tk
tulevat $_GET-muuttujista. Aluksi muodostetaan yhteys tietokantaan, noutaaksemme nykyisen tilanteen.
SELECT * FROM Tiedot WHERE Jakso = '{$jakso}' AND Tuotantokausi = '{$tk}'
Sitten laskemme keskiarvon $ka
yhteen GET:n muuttujan type
kanssa. Jos siis aluksi $ka
oli 2.5 ja annettu ääni on 3, tuloksena tällöin 2.75, joka pyöristetään lähimpään 0.5:een (tuloksena 3). Ja tulostetaan...
$number = $ka+$_GET[type]; $number = $number/2; $rounding = 0.5; $rounded = round($number/$rounding)*$rounding; print "k.a. ".$rounded." - ".$aania." arvostelu";
Lopuksi tiedot tallennetaan tietokantaan. Luulen, että tässä on se itse vikakohta. Mikä mättää?
mysql_select_db("2957_jaksot", $paivita); mysql_query("UPDATE Tiedot SET `KA` = '{$ka}' WHERE `Jakso` = '{$jakso}' AND `Tuotantokausi` = '{$tk}'"); #mysql_query("UPDATE Tiedot SET Ääniä = '{$aania}' WHERE Jakso = '{$jakso}' AND Tuotantokausi = '{$tk}'"); mysql_close($paivita);
Olen kyllä yhdistänyt tässäkin vaiheessa tietokantaan, mutta en nyt laittanut kyseistä riviä tähän näkyville.
Ongelmani on siis: Tiedot eivät tallennu tietokantaan, vaikka pyyntö sinne tehdäänkin.
Numeroita ei pitäisi ympäröidä heittomerkeillä, tosin mysql kaiketi antaa tämän anteeksi. Mutta sitten pieni ihmetyksen aihe, että miksi ihmeessä päivität keskiarvon kantaan? Sehän kannattaa ehdottomasti laskea kyselyn yhteydessä annetuista äänistä. $_GET[type] ei ole sallittu ilmaisu, vaan tulisi käyttää $_GET['type'] merkintää.
Lopuksi vielä sellainen vinkki, että helppo debuggaus on tulostaa muuttujien arvoja ja katsoa onko tuloste sellainen kuin pitääkin.
Vaihdoin nyt $_GET['type']
ja poistin numeroiden ympäriltä heittomerkit. Miksi ihmeessä en päivittäisi keskiarvoa kantaan? Luulisitko, että toimisi vaikka laskisikin toisella tavalla?
Jos ymmärsin oikein, tarkoitit, että jokaisella äänestyskerralla lisätään lukuun annettu ääni, joka jaettaisiin annettujen äänien määrällä, vasta siinä vaiheessa kuin sivu ladataan.
Ei se tallennustapa varmaan toimivuuteen vaikuta mitenkään, mutta tietokannan ideana on säilyttää annetut äänet ja niistä voidaan koosta erilaisia tunnuslukuja. Voisit esimerkiksi esittää äänien jakauman tai keskihajonnan, mediaanin, keskiluvun jne. Kuitenkin millainen kysely on tulostettuna?
Itse laittaisin tietokantaan kaksi saraketta, toisen tähtien yhteismäärälle ja toisen tähtien antajien määrälle. Tulostusvaiheessa vasta laskisin jakamalla tähtien määrän antajien määrällä.
Tarkoitukseni ei ole palvelussani esittää tietoa, jolla ei loppujen lopuksi tehdä mitään.
Nyt tipuin muutenkin kärryiltä.
Teuro kirjoitti:
ja niistä voidaan koosta erilaisia tunnuslukuja
Tällä hetkellä käyttäjä näkee seuraavan:
k.a. 2 - 1 arvostelu
Macro, esitin tuon asian jo aiemmin.
Petja kirjoitti:
Jos ymmärsin oikein, tarkoitit, että jokaisella äänestyskerralla lisätään lukuun annettu ääni, joka jaettaisiin annettujen äänien määrällä, vasta siinä vaiheessa kuin sivu ladataan.
Eikö fiksuinta olisi kuitenkin rakenne, jossa olisi arvostelukohteen id ja toisessa annettu ääni. Nyt voisi esittää keskiarvon jokaiselle arvostelukohteelle erikseen. Esim.
<?php $sql = "SELECT nimi, AVG( aani ) AS keskiarvo FROM arvostelut, kohteet WHERE kohteet.id = arvostelut.arvostelukohde GROUP BY arvostelut.arvostelukohde"; ?>
Minulle on tämä MySQL syvemmältä ihan hepreaa. Pystytkö selittämään tuon sinun SQL-lausekkeesi minulle?
Ainut, mitä englanninkielen taidolla tästä selville saan on AVG = average = keskiarvo.
Petja kirjoitti:
Minulle on tämä MySQL syvemmältä ihan hepreaa. Pystytkö selittämään tuon sinun SQL-lausekkeesi minulle?
Joo valitaan kohteen nimi ja keskiarvo tauluista arvostelut ja kohteet missä kohteen id numero on sama kuin arvostelutaulun kohdeviittaus, jotka ryhmitellään siten että arvostelutaulun jokainen arvostelukohde joka on sanut ainakin yhden äänen tulostuu kerran ja vain kerran.
Esimerkkitauluni tuotti tällaisen tuloksen.
nimi keskiarvo traktori 3.7500 puimuri 4.8000 tietokone 5.0000 leivänpaahdin 5.0000
Taulun kohteet sisältö puolestaan on tällainen
1 traktori 2 puimuri 3 tietokone 4 leivänpaahdin
Taulun arvostelut sisältö taas on tällainen
arvostelu- kohde aani id 1 5 1 1 3 2 1 4 3 2 5 4 2 3 5 2 4 6 2 6 7 1 3 8 3 5 9 4 5 10 2 6 11
Eli tässä tapauksessa on kyse jaksojen arvostelusta. Jokaisella jaksolla on yksilöitävä tunnus, joka tulee tuotantokausi x jakso. Esimerkiksi 1x3 tarkoittaisi 1. tuotantokauden 3. jaksoa. Jaksotiedot sijaitsevat taulussa Tiedot
.
Luonko nyt siis uuden taulun Arvostelut
?
Edit: Viestiä muutettu.
No saa sen toimimaan yhdelläkin taululla, mutta hiukan siinä menetetään tietokannasta saatavaa hyötyä. Eli siis yhdessä taulussa olisi kohteen nimi ja annettu ääni. Hakulause tulisi silloin muotoon.
<?php $sql = "SELECT arvostelukohde, AVG( aani ) AS keskiarvo FROM arvostelut GROUP BY arvostelukohde"; ?>
Nyt aloin vähitellen ymmärtämään mitä ajat takaa. Luepa vielä edellinen viestini, koska kirjoitin sen uudelleen. Loin nyt uuden taulun.
CREATE TABLE `2957_jaksot`.`Arvostelut` ( `ID` INT NOT NULL AUTO_INCREMENT , `Kohde` TEXT NOT NULL , `Aani` INT NOT NULL , PRIMARY KEY ( `ID` ) ) ENGINE = MYISAM ;
Miten nyt jatkan?
Voidaanko jaksot tunnistaa esimerkiksi päivämäärästä? Tällöin selviät aika pienillä muutoksilla. Kirjoittelen kohta toimivan pätkän kunhan saan aikaiseksi. Voit kysellä ircin puolella lisää ircnet@teuro
Jaksoilla on alkuperäinen ensiesityspäivä (USA) ja suomalainen ensiesityspäivä. Niiden perusteella en kuitenkaan jaksoja yksilöisi, paitsi jos muita ratkaisuja ei ole.
Aah my bad käsitin jakson väärin. Jakso tarkoittaa jonkun sarjan tiettyä jaksoa. Luulin jakson tarkoittavan tiettyä jaksoa vuodesta.
Erehdyksiä sattuu. Mietenkin, että tarvitseeko tässä mainita kyseessä olevan tv-sarja. En kuitenkaan maininnut, kun oletin sinun jo ymmärtävän. ;-)
Noh... Mitens nyt?
No sitten melkein tuo mun eka vinkki voisi olla ihan sopiva. Eli siis yhdessä taulussa on jaksojen nimi ja id. Toisessa taulussa puolestaan olisi arvostelut ja jakson tunniste. Sitten vain tuolla haulla otetaan ne tiedot jotka halutaan.
Kuinkas tätä koodipuolta toteutetaan?
No tällainen syntyi ja kokeilun perusteella toimii aivan odotetusti.
<?php $yhteys = mysql_connect("localhost", "root"); mysql_select_db("arvostelut"); if (isset($_GET['id'])) { $id = siivoa_syote($_GET['id']); $aani = siivoa_syote($_GET['aani']); $sql = "INSERT INTO arvostelut (arvostelukohde, aani) VALUES($id, $aani)"; mysql_query($sql); } $sql = "SELECT kohteet.id, nimi, AVG( aani ) AS keskiarvo FROM arvostelut, kohteet WHERE kohteet.id = arvostelut.arvostelukohde GROUP BY arvostelut.arvostelukohde"; $tulos = mysql_query($sql); ?> <table> <?php while ($rivi = mysql_fetch_assoc($tulos)) { echo "<tr><td>" . $rivi['nimi'] . "</td><td>" . $rivi['keskiarvo']. "</td></tr>"; echo "<tr><td><p>"; for ($i = 1; $i <= 5; ++$i) { echo "<a href=\"?aani={$i}&id={$rivi['id']}\"> {$i}</a>"; } echo "</p></td></tr>"; } ?> </table>
Eli voitko vielä kertoa lyhyesti, mitä muutoksia minun tarvitsee tehdä phpMyAdminissa, jotta tämä sinun koodipätkäsi toimisi halutulla tavalla? Jaksotiedot siis edelleen taulussa Tiedot
ja arvostelut Arvostelut
-taulussa. Koodiinkin voin joutua tekemään pikku muutoksia.
Jos kenttien nimet osuvat ei tarvitse muuttaa kuin tuosta koodista noiden taulujen nimet vastaamaan kantaasi. Eli arvostelut -> Arvostelut ja kohteet -> Tiedot.
Ok. Laitan koodin pian toimintaan, mutta vielä kun silmämääräisesti koodia tutkin, se näyttäisi tulostavan jonkinlaisen taulukon ja linkin. Käyttäjän näkemä lopputulos saisi olla kylläkin
k.a. (keskiarvo tähän) - (arvostelujen määrä tähän) arvostelua
esim.
k.a. 2.5 - 0 arvostelua
Niin, ja vielä siitä. Tuleeko tämä koodisi aani.php
:hen, jota kutsutaan Ajaxilla, kun käyttäjä klikkaa tähteä?
Ok eli käyttäjä ei voi arvostella jaksoa? Sitten korvaa tuo tulostus tällä versiolla.
<?php $sql = "SELECT kohteet.id, nimi, AVG( aani ) AS keskiarvo, COUNT(*) AS kpl FROM arvostelut, kohteet WHERE kohteet.id = arvostelut.arvostelukohde GROUP BY arvostelut.arvostelukohde"; $tulos = mysql_query($sql); while ($rivi = mysql_fetch_assoc($tulos)) { echo "<p>{$rivi['nimi']} {$rivi['keskiarvo']} - {$rivi['kpl']}</p>"; } ?>
Teuro kirjoitti:
Ok eli käyttäjä ei voi arvostella jaksoa?
Siis... täh...?
Sitähän varten nämä tähdet ovat, että käyttäjä voi arvostella jakson.
Selitänpä vielä:
Kun käyttäjä saapuu jaksotietosivulle hän näkee jakson tiedot ja arvostelutähdet. Käyttäjän napsauttaessa tähteä, tehdään pyyntö Ajaxille, joka hakee sivun aani.php
. aani.php
:n tarkoitus on tallentaa tiedot tietokantaan ja tulostaa sitten nämä ko. tiedot. Ja Ajaxissahan käyttäjä näkee, mitä noudettu sivu palauttaa. Ja jos se tällä kertaa palautti
k.a. 3 - 1 arvostelu
näkee käyttäjä sen.
Edit:
Taulussa Arvostelut
on kolme saraketta ID
, Kohde
, Aani
. Muuttelin koodia, mutta ruikuittaa silti:
Warning: mysql_fetch_assoc(): supplied argument is not a valid MySQL result resource in /var/www/virtual/petjatouru.arkku.net/futurama/
No jos sitten vain korvaat tuon numeron tulostamisen sillä tähdellä? Viimeinen virhe tarkoittaa, että sinulla jokin virhe tuossa kyselyssä edelleen kannattaa tulostaa se näytölle ja tutkia mitä se sisältää ja samalla tulostaa mysql_error() funktion antama virheilmoitus.
Olen nyt saanut (itse asiassa jo eilen) toimimaan skriptin. Koodasin kaiken alusta asti.
Teuro kirjoitti:
Voisit esimerkiksi esittää äänien jakauman tai keskihajonnan, mediaanin, keskiluvun jne.
Voisitko vielä selittää, mihin näitä tarvitsisi?
Eikö käyttäjälle riitä pelkkä keskiarvon näkeminen?
Kyllähän keskiarvokin riitää, mutta ne muut ovat myös mielenkiintoisia ja kertovat kaikki yhdessä paljon enemmän, esim. keskihajonta kuinka samaa/eri mieltä käyttäjät ovat.
Keskiarvo on kyllä ainoa oikea tähtijärjestelmään :)
Itse tein juuri arvostelusysteemin eräälle nettikaupalle. Tuotteet oli tuote.php?id=[id] ja tallennettuna taulussa tuotteet.
tein taulun arvostelut, jossa sarakkeet: arvosana|tuoteid|id
tuote.php:
<?php $arvosanat = mysql_query("SELECT * FROM arvostelut WHERE tuoteid='mysql_real_escape_string($_GET[id])'"); $maara = mysql_num_rows($arvosanat); $num = mysql_query("SELECT SUM(arvosana) FROM arvostelut WHERE tuoteid='mysql_real_escape_string($_GET[id])'"); $keskiarvo = round($num/$maara,2); print 'Tuotteen keskiarvo on '.$keskiarvo.', arvostele itse: '; ?>
Kirjoitin tuon vain muistista ja muistaakseni tein sen jotenkin selvemmin itse oikeaan koodin. Koodi yläpuolella on aika sönkköä ja ehkä pitkistettyä, mutta sen tarkoitus on olla suuntaa antava. :)
edit: Hups, en huomannut postausta jossa ilmoitit koodin olevan jo kunnossa. Noh, tuossa oma tyylini..
Clacier: En sano pahalla, mutta tuo on aika järjetön ratkaisu laskea käsin keskiarvoa, kun kanta tarjoaa valmiin funktion tuolle. Et tarvitse myöskään kahta kyselyä, koska voit kysellä summan ja määrän samalla kyselyllä. Ratkaisun keksinet itsekin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.