Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: [AJAX] [PHP] [MySQL] Arvosteluskripti [noob]

Sivun loppuun

Petja [19.02.2011 08:52:27]

#

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.

Teuro [19.02.2011 09:11:21]

#

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.

Petja [19.02.2011 09:35:51]

#

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.

Teuro [19.02.2011 09:39:36]

#

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?

Macro [19.02.2011 09:41:20]

#

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

Petja [19.02.2011 09:45:57]

#

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.

Teuro [19.02.2011 09:46:00]

#

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

Petja [19.02.2011 09:50:25]

#

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.

Teuro [19.02.2011 10:00:25]

#

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

Petja [19.02.2011 10:10:20]

#

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.

Teuro [19.02.2011 10:23:36]

#

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

Petja [19.02.2011 10:30:02]

#

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?

Teuro [19.02.2011 10:33:23]

#

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

Petja [19.02.2011 10:36:16]

#

Jaksoilla on alkuperäinen ensiesityspäivä (USA) ja suomalainen ensiesityspäivä. Niiden perusteella en kuitenkaan jaksoja yksilöisi, paitsi jos muita ratkaisuja ei ole.

Teuro [19.02.2011 10:39:20]

#

Aah my bad käsitin jakson väärin. Jakso tarkoittaa jonkun sarjan tiettyä jaksoa. Luulin jakson tarkoittavan tiettyä jaksoa vuodesta.

Petja [19.02.2011 10:40:42]

#

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?

Teuro [19.02.2011 10:55:12]

#

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.

Petja [19.02.2011 10:57:56]

#

Kuinkas tätä koodipuolta toteutetaan?

Teuro [19.02.2011 11:16:10]

#

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}&amp;id={$rivi['id']}\">  {$i}</a>";
	}
	echo "</p></td></tr>";
}
?>

</table>

Petja [19.02.2011 11:21:24]

#

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.

Teuro [19.02.2011 11:27:37]

#

Jos kenttien nimet osuvat ei tarvitse muuttaa kuin tuosta koodista noiden taulujen nimet vastaamaan kantaasi. Eli arvostelut -> Arvostelut ja kohteet -> Tiedot.

Petja [19.02.2011 11:33:34]

#

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

Teuro [19.02.2011 11:37:43]

#

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

Petja [19.02.2011 11:43:39]

#

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/htdocs/aani.php on line 27

Teuro [19.02.2011 12:27:48]

#

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.

Petja [21.02.2011 15:50:16]

#

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?

Hennkka [21.02.2011 16:50:23]

#

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

Clacier [21.02.2011 23:56:01]

#

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

Teuro [22.02.2011 08:39:56]

#

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.


Sivun alkuun

Vastaus

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

Tietoa sivustosta