Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Tietojen haku tietokannasta + niiden järjestäminen oikein

Sivun loppuun

Jonttu [31.10.2012 19:27:00]

#

Tietokantani rakenne:

           T H E   I N T E R S E C T

kayttajat          ystavapyynnot         postaukset
-id                -lahettajan_id        -lahettajan_id
-nimi              -vastaanottajan_id    -postaus
-sahkoposti        -status               -lahettajan_nimi
-salasana
Kayttajat  id   nimi    sahkoposti            salasana
            1   Erkki   erkki@outlook.com     12345
            2   Kaveri  kaveri@outlook.com    123456
			3 	Trolli	spammi@spammi.com	  123123

ystavapyynnot  lahettajan_id   vastaanottajan_id    status
                    1                  2              OK
                    2                  1              OK

postaukset     lahettajan_id   postaus               A   I   K   A
                    1          Tulostui oikein   10.10.2012   19:50:00
                    2          VÄÄRIN TULOSTUI   11.10.2012   20:00:00
                    1          Tulostui oikein   9.10.2012    19:50:00
 					3		   Tämä EI saa 		 10.10.2012	  00:00:00
								tulostua

PHP-KOODI

	// YHDISTÄ TIETOKANTAAN
mysql_connect("localhost", "root", "XXXXX")or die("Yhdistäminen tietokantaan epäonnistui: Voisitko ilmoittaa siitä meille?");
mysql_select_db("TheIntersect")or die("Ei voida valita tietokantaa: Voisitko ilmoittaa siitä meille?");

$omaid = $_SESSION['id'];
$hae = mysql_query("SELECT * FROM ystavapyynnot WHERE status='ok' AND lahettajan_id='$omaid'")OR DIE(mysql_error());
while($row = mysql_fetch_array($hae))
	{
		$kaverit1 = $row['vastaanottajan_id'];

//Haetaan postaukset
$haepostaukset = mysql_query("SELECT * FROM postaukset WHERE lahettaja='$kaverit1'") OR DIE(mysql_error());
					while($row = mysql_fetch_array($haepostaukset))
					{
						$postaus = $row['viesti'];
						$lahettaja = $row['lahettaja'];
						$lahettajan_nimi = $row['nimi'];
						$postauksen_id = $row['id'];
?>

					<!--POSTAUS JA NIIDEN SISÄLTÖ -->
<div class="lahettajan_nimi">
<a class="lahettajan_nimi" href="profile.php?id=<?php print $lahettaja; ?>"><?php print htmlspecialchars($lahettajan_nimi);?></a>
</div>

<div class="postauksen_sisalto"><?php print $postaus; ?>
</div>
		<?php
// WHILET LOPPUU
                  }
     }
?>

Tulostus:

POSTAUKSET


Erkki 10.10.2012  19:50
  Tämä tulostuu oikein

Erkki 9.10.2012   19:50
  Tämäkin tulostuu oikein

Kaveri 11.10.2012 20:00
  TÄMÄ TULOSTUU VÄÄRÄÄN PAIKKAAN, TÄMÄN PITÄISI OLLA YLIMPÄNÄ KOSKA TÄMÄ ON LÄHETETTY VIIMEKSI

Olisko neuvoa miten saisin postaukset oikeaan järjestykseen?

EDIT:
Eli koodin tarkoitus on aluksi katsoa ketkä ovat henkilön Erkki kavereita.
Sen jälkeen koodi hakee postaukset tietokannasta ja näyttää Erkin kavereiden postaukset.
Muiden kuin kaverien postauksia ei saa näyttää.

Ripe [31.10.2012 20:27:17]

#

Kannattaisi mieluummin käyttää Pdota.
Sillä koodista tulee tietoturvallisempaa ja omasta mielestäni myös selkeämpää.
Esimerkiksi:

$yhteys = new PDO("mysql:host=localhost;dbname=tietokanta", "käyttäjä", "salasana");
$sql = "SELECT * FROM taulu WHERE joku = ?";
$kysely = $yhteys->prepare($sql);
$kysely->execute(array($jokumuuttuja));

Teuro [31.10.2012 21:48:24]

#

Miksi olet tehnyt noita omia päivämäärä- ja aikakenttiä? kyllä kannan oma tekniikka osaa järjestäjää rivit oikein, kunhan et tee noita omia juttuja.

Ripe [31.10.2012 22:13:18]

#

Eli ota aikapaiva, aikatunnit ja aikasekunnit pois ja tilalle aika jonka tyyppi on datetime tai timestamp. Sitten vain order by aika desc

Jonttu [01.11.2012 17:32:00]

#

Koodissa nyt käytössä PDO.

<?php
try {
    $yhteys = new PDO("mysql:host=localhost;dbname=theintersect", "root", "XXXX");
} catch (PDOException $e) {
    die("VIRHE: " . $e->getMessage());
}
// YHTEYS 1
$yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$yhteys->exec("SET NAMES latin1");
$kysely = $yhteys->prepare("SELECT * FROM postaukset, ystavapyynnot");
$kysely->execute();

while ($row = $kysely->fetch()) {
?>
<a href="profile.php?id=<?php print $row["lahettaja"]; ?>">
	<?php print htmlspecialchars($row["nimi"]).$row["aika"];?>
</a>

<div class="postauksen_sisalto">
	<?php print $row["viesti"]; ?>
</div>
<br />
<?
}
?>

Tulostus:

Erkki 10.10.2012  19:50
  Tämä tulostuu oikein

Erkki 10.10.2012  19:50
  Tämä tulostuu oikein

Erkki 9.10.2012   19:50
  Tämäkin tulostuu oikein

Erkki 9.10.2012   19:50
  Tämäkin tulostuu oikein

Kaveri 11.10.2012 20:00
  TÄMÄ TULOSTUU VÄÄRÄÄN PAIKKAAN, TÄMÄN PITÄISI OLLA YLIMPÄNÄ KOSKA TÄMÄ ON LÄHETETTY VIIMEKSI

Kaveri 11.10.2012 20:00
  TÄMÄ TULOSTUU VÄÄRÄÄN PAIKKAAN, TÄMÄN PITÄISI OLLA YLIMPÄNÄ KOSKA TÄMÄ ON LÄHETETTY VIIMEKSI

Kaikki postaukset tulostuvat kahteen kertaan?

Ripe [01.11.2012 18:11:34]

#

Onko ORDER BY aika DESC käytössä? Pitäisi tulla ainakin oikein päin viestit. Tuohon tuplaantumiseen en oikein osaa sanoa mitään, sama on tullut itselläkin vastaan, mutta en muista miten korjasin ongelman.

Metabolix [01.11.2012 18:18:14]

#

Tuplaantumisen syy on, että kyselyssäsi on mukana kaksi taulua, joista toisessa on kaksi riviä, vaikka kyselyssä pitäisi olla vain yksi taulu tai sopiva liitosehto tai UNION. Väärän järjestyksen syy on, että et pyydä tuloksia missään tietyssä järjestyksessä. Järjestäminen ei myöskään onnistu, jos tiedot ovat tietokannassa väärässä muodossa; päivämäärän ja ajan oikea muoto on DATETIME tai TIMESTAMP.

Jonttu [01.11.2012 19:03:24]

#

Koodin pitäisi tulostaa henkilön "Erkki" kavereiden postaukset aikajärjestyksessä.

$kysely = $yhteys->prepare("SELECT * FROM postaukset, ystavapyynnot");

Jos on tällainen kysely, voiko siihen lisätä ORDER BY:ta?

Itsellä ainakin tuli virheilmoituksia jos lisäsin ORDER BY:n

latenleffahylly [01.11.2012 20:20:15]

#

http://www.w3schools.com/sql/sql_orderby.asp

Esimerkki: Jos jaksat/ehdit lukea rauhassa läpi.

Jonttu [01.11.2012 21:23:57]

#

latenleffahylly kirjoitti:

http://www.w3schools.com/sql/sql_orderby.asp

Esimerkki: Jos jaksat/ehdit lukea rauhassa läpi.

Olen käynyt nuo W3Schoolsin oppaat läpi aikaisemminkin.

Sain ORDER BY:n nyt toimimaan, mutta tulostaa edelleen kaikki postaukset 2 kertaa

Kaveri 11.10.2012 20:00
  VIESTI TULOSTUU KAHTEEN KERTAAN?

Kaveri 11.10.2012 20:00
  VIESTI TULOSTUU KAHTEEN KERTAAN?

Erkki 10.10.2012  19:50
  MIKSI?

Erkki 10.10.2012  19:50
  MIKSI?

Erkki 9.10.2012   19:50
  MITEN SAAN KORJATTUA

Erkki 9.10.2012   19:50
  MITEN SAAN KORJATTUA

XYZ [01.11.2012 22:26:38]

#

http://www.w3schools.com/sql/sql_join.asp
http://www.lpt.fi/it/opetus/tietokannat/liitokset.html
http://appro.mit.jyu.fi/doc/tiedonhallinta/sql/dml/index17.html

Jonttu [02.11.2012 06:55:59]

#

Nyt sain toimimaan lisäämällä if-lauseen ennen tulostusta:

if($row["lahettajan_id"] == $_SESSION["id"] && $row["vastaanottajan_id"] == $row["lahettaja"]){
//TULOSTUS
}

Metabolix [02.11.2012 07:53:21]

#

Jonttu kirjoitti:

Sain ORDER BY:n nyt toimimaan, mutta tulostaa edelleen kaikki postaukset 2 kertaa

Kerroin jo syyn. Oletko lukutaidoton vai etkö vain viitsi lukea vastauksia, vai oletko jotenkin todennut väitteeni vääräksi?

Jonttu [02.11.2012 15:33:15]

#

Metabolix kirjoitti:

Jonttu kirjoitti:

Sain ORDER BY:n nyt toimimaan, mutta tulostaa edelleen kaikki postaukset 2 kertaa

Kerroin jo syyn. Oletko lukutaidoton vai etkö vain viitsi lukea vastauksia, vai oletko jotenkin todennut väitteeni vääräksi?

Anteeksi tyhmyyteni (En ollut huomannut ylempää kommenttiasi)

Mutta nyt sain pelittämään koko systeemin, postaukset tulevat niinkuin pitääkin ja oikeassa järjestyksessä:

<?php
try {
    $yhteys = new PDO("mysql:host=localhost;dbname=theintersect", "root", "XXXXX");
} catch (PDOException $e) {
    die("VIRHE: " . $e->getMessage());
}
// YHTEYS PDO
$yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$yhteys->exec("SET NAMES latin1");
$kysely = $yhteys->prepare("SELECT * FROM ystavapyynnot, postaukset ORDER BY aika DESC");
$kysely->execute();

while ($row = $kysely->fetch()) {
if($row["lahettajan_id"] == $_SESSION["id"] && $row["vastaanottajan_id"] == $row["lahettaja"]){
?>
<a href="profile.php?id=<?php print $row["lahettaja"]; ?>">
	<?php print htmlspecialchars($row["nimi"]).$row["aika"];?>
</a>

<div class="postauksen_sisalto">
	<?php print $row["viesti"]; ?>
</div>
<br />
<?
}
?>

Tulostus:

Kaveri 11.10.2012 20:00
  Kaikki tulostuvat nyt oikein oikeassa järjestyksessä ja rivit eivät enää tuplaannu. :)

Erkki 10.10.2012  19:50
  Tämä tulostuu oikein

Erkki 9.10.2012   19:50
  Tämäkin tulostuu oikein

Macro [02.11.2012 15:43:23]

#

Sun koodisi on kyllä ihan pielessä. Haet kaiken datan postaukset- ja ystavapyynnot-tauluista? Tietokantarakenteestasi ei myöskään käy selville, että miten taulut ystavapyynnot ja postaukset liittyvät toisiinsa. Valaisisitko vähän?

Jos tarkoitus on näyttää käyttäjälle järjestelmässä lähetettyjä ystäväpyyntöjä, niin olisiko järkevämpää säilöä samaan tauluun lähettän id, vastaanottajan id ja viestin sisältö? Silloin data voitaisiin hakea tälläisellä kyselyllä

SELECT
	lahettaja_id,
    aika,
	viesti
FROM
	ystavapyynnot
WHERE
	vastaanottaja_id = 123
ORDER BY
	aika DESC

Huomaathan, että kun aika-sarakkeesi ei ole timestamp- eikä datetime-muodossa, niin ORDER BY järjestää ne väärin, jos se on data on vaikka muodossa dd.mm.yyyy HH:mm.

Jos pistäisit ajat tietokannassa esim. datetime-muodossa (sarakkeen tyypiksi datetime, lisäyshetkellä NOW() antaa oikean arvon sarakkeelle), niin järjestyskin pysyisi oikeana. Myös jälkikäsittely helpottuu (mitä jos haluat päivämäärät toiseen muotoon?).

Jonttu [02.11.2012 19:10:43]

#

Macro kirjoitti:

Sun koodisi on kyllä ihan pielessä. Haet kaiken datan postaukset- ja ystavapyynnot-tauluista? Tietokantarakenteestasi ei myöskään käy selville, että miten taulut ystavapyynnot ja postaukset liittyvät toisiinsa. Valaisisitko vähän?

Eli koodi hakee henkilön A kaverit "ystavapyynnot"-taulusta ja viestit "postaukset"-taulusta.
Koodi tarkistaa onko postauksen lähettäjä kaveri, jos on koodi tulostaa postauksen. Jos ei ole kaveri koodi ei tulosta mitään.
Muiden kuin kaverien postaukset eivät näy A:lle

Macro [02.11.2012 19:23:44]

#

Pitäiskö sillon mahdollisesti käyttäjiä estää lähettämästä viestejä, ettei tietokanta täyttyisi spämmiviesteistä?

Eikö kavereille olisi loogisempaa luoda oma taulu kaverit?

XYZ [02.11.2012 19:25:15]

#

Jonttu kirjoitti:

Eli koodi hakee henkilön A kaverit "ystavapyynnot"-taulusta ja viestit "postaukset"-taulusta.

Koodi tarkistaa onko postauksen lähettäjä kaveri, jos on koodi tulostaa postauksen. Jos ei ole kaveri koodi ei tulosta mitään.

Muiden kuin kaverien postaukset eivät näy A:lle

KYSELY hakee "ystavapyynnot"-taulusta ja "postaukset"-taulusta yhteensä:
ystavapyynnot( kaikki rivit ) * postaukset ( kaikki rivit ). Onkohan jotain pielessä?

Koodissa yrität sitten korjata virheellistä kyselyä. Ei näin.

Muuta taulujen rakennetta Macro:n esittämällä tavalla tai lue antamani linkit.

Edit ennen lähetystä: Jos käyttäjä voi lähettää yleisiä postauksia kaikille kavereille, ei Macron rakenne oikein toimi.

Opettele nyt vaan se liitosten käyttö.

Metabolix [02.11.2012 19:28:55]

#

Tässähän ilmeisesti "korjaukseksi" keksityn if-lauseen sisältö kuuluisi SQL-kyselyn WHERE-osaan.

XYZ [02.11.2012 20:25:21]

#

$kysely = $yhteys->prepare("SELECT postaukset.lahettajan_nimi,postaukset.aika from ystavapyynnot,postaukset WHERE
( ystavapyynnot.lahettajan_id = postaukset.lahettajan_id OR
ystavapyynnot.vastaanottajan_id = postaukset.lahettajan_id )
AND ystavapyynnot.status = 'OK' AND postaukset.lahettajan_id != ?
AND ( ystavapyynnot.lahettajan_id = ? OR ystavapyynnot.vastaanottajan_id = ? ) ORDER BY aika DESC");

$user =  (int) $_SESSION["id"];

$kysely->bindParam(1, $user, PDO::PARAM_INT );
$kysely->bindParam(2, $user, PDO::PARAM_INT  );
$kysely->bindParam(3, $user, PDO::PARAM_INT  );
$kysely->execute();

Aika ruma, mutta ehkä sinne päin.

The Alchemist [03.11.2012 09:10:31]

#

Se on ruma, koska et kirjoita siistiä koodia. Toisekseen se on ruma myös, koska tietokanta-arkkitehtuuri ei ole optimaalinen.

$sql = '
    SELECT
        b.lahettajan_nimi,
        b.aika

    FROM kaverit a
        INNER JOIN postaukset b ON a.kaveri_id = b.lahettajan_id

    WHERE a.kayttaja_id = ?
    ORDER BY b.aika DESC
';

$user = $_SESSION['user_id'];
$smt = $pdo->prepare($sql);
$smt->execute(array($user));

Jokseenkin parempi, tosin oikeaoppisesta sisentämisestä voi aina kiistellä.

Teet siis uuden taulun ("kaverit"), johon lisäät hyväksyttyjen kaveripyyntöjen pohjalta syntyneet kaverisuhteet. Jokaisesta kaverisuhteesta tulee kaksi riviä, mutta nähdäkseni se on parempi niin, kuin ruveta arpomaan joinissa, että minkä sarakkeen suhteen rivit yhdistetään.

En itse käyttäisi bindParam()-kutsua kuin silloin, kun arvon tyypillä on oikeasti jotain väliä (esimerkiksi LIMIT-ehdossa). Turhaa toistoa ja sotkua.

P.S. Yritin joskus googlettaa SQL-kyselyiden sisentämisen "best practises" -ohjeita, mutta hyvin usein ihmiset perustelivat omaa valintaansa koodin lukemisen helppoudella, mutta samalla tekivät kyselyiden kirjoittamisesta vaikeampaa, mikä tosin riippunee myös editorin ominaisuuksista. Oma sisennystyylini sallii hyödyntää editorin automaattista sisennystä samalla kuitenkin pitäen kyselyt siisteinä ja luettavina.


Sivun alkuun

Vastaus

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

Tietoa sivustosta