Autor Zpráva
Itran
Profil
Nevím si rady. Pořád se mi nedaří udělat ten správný dotaz do MySQL.
Mám fórum. Uživatelé vkládají dotazy a ke každému dotazu je možné psát odpovědi.

Mám 2 tabulky pro fórum:
V první tabulce jsou dotazy, ve druhé tabulce jsou odpovědi k dotazům.

1. tabulka id, titulek, dotaz, datum, jmeno
2. tabulka k_id, odpoved, datum, jmeno

k_id znamená, ke kterému id z první tabulky se vztahuje odpověď.

Potřebuju vypsat 10 dotazů, ve kterých jsou nejnovější odpovědi. Řazeno dle datumu. Samozřejmě se musí případně vypsat i dotaz, které ještě nemá žádnou odpověď.

Vypsat by se měl titulek dotazu (k němu nejnovější odpověď nebo znění dotazu - pokud ještě žádnou odpověď nemá), dále datum a jméno.

Vím, že se tu podobné věci řešily. Zkoušel jsem všechno možné, ale zatím bez úspěchu. Mohl by někdo poradit. Moc děkuju.
juriad
Profil
Takto:
SELECT d.*,
  COUNT(o.k_id) pocet,
  COALESCE(MAX(o.datum), d.datum) posledni
FROM dotazy d
  LEFT JOIN odpovedi o
    ON o.k_id = d.id
GROUP BY d.id
ORDER BY posledni DESC
LIMIT 10

Ukázka (zjednodušená o nepotřebné sloupce):
http://sqlfiddle.com/#!2/1c0c2/4
Itran
Profil
juriad, díky. Toto jsi už někde psal. Jenže tento příklad mi nevypisuje nejnovější odpověď, ale vypíše znění dotazu. Potřeboval bych vypsat TITULEK a k němu tu nejnovější odpověď.
juriad
Profil
Itran:
Pokud přidáš auto_increment id do tabulky odpovědí, tak to lze takto:
http://sqlfiddle.com/#!2/4bbee6/3
V opačném případě je to velice obtížné, neboť by mohli dva uživatelé přispět ve stejné sekundě, a z toho důvodu by existovaly dvě odpovědi s maximálním datumem, a řádek by se zobrazil dvakrát (pokaždé s jinou poslední odpovědí).
Itran
Profil
Díky moc. Teď to funguje správně. I když ten dotaz vypadá složitě. ID v té druhé tabulce mám, takže je to ok. Ještě to zkusím otestovat v plném provozu. Toto bych nezvládl ani náhodou. Máš můj obdiv.
juriad
Profil
Tím poddotazem m si zjistíš obecné informace o odpovědích (počet a id posledního).
Jakmile znáš id posledního, už si ho jen přijoinuješ o a pokud existuje, tak si z něj vytáhneš informace.
Ta funkce COALESCE vrací první neNULLový argument, tím zajistím, že pokud odpověď neexistuje, vrátí informaci ze samotného dotazu.


Pokud bys měl problém s výkonem, šlo by přidat indexy pro rychlejší vyhledávání.

Případně by šlo přidat sloupec poslední typu boolean k odpovědi. Pak bys rovnou našel odpověď, která je pre]poslední[/pre]. Při přidání odpovědi bys v transakci provedl UPDATE předchozí poslední odpovědi na false a následně vlastní INSERT nové odpovědi.
Počet odpovědí si můžeš pamatovat přímo v dotazu v novém sloupci počet odpovědí. V transakci při INSERTU bys provedl ještě UPDATE počtu odpovědí v tabulce dotazy.

S těmito dvěma změnami by dotaz byl rychlejší, ale za cenu pomalejšího ukládání odpovědí.
Pokud nebuduješ extrémně výkonně náročné fórum, tyto změny neprováděj.
Itran
Profil
To fórum vlastně už běží. Jen jsem ho chtěl trochu zmodernizovat. Teď mám dotazy i odpovědi v jedné tabulce společně. A počet odpovědí mám taky přímo jako sloupec. Jen to dělalo nepřesnosti, když jsem nějaké odpovědi ručně mazal. Fórum má kolem 80000 řádků. Na svém PC jsem tvůj dotaz testoval na 5000 řádcích a bez indexů to trvalo asi 15 sekund. S indexy "ihned".

Doteď jsem používal něco takového:

$vysledek = MySQL_Query("SELECT k_id, datum, text FROM tabulka ORDER BY datum DESC");
$citac=0;
while ($zaznam = MySQL_Fetch_Row($vysledek)):
if(@In_Array($zaznam[0], $IDtemp)) continue;
$IDtemp[]=$zaznam[0];
$vysledek2 = MySQL_Query("SELECT titulek FROM tabulka WHERE id='".$zaznam[0]."'");
$zaznam2 = MySQL_Fetch_Row($vysledek2);
//následuje výpis dat
$citac++;
if($citac>10) break;
endwhile;
Asi to nazveš prasárnou.
Alphard
Profil
Itran:
Asi to nazveš prasárnou.
Tak by to nazval každý :-) To co radil juriad nemusí být pro každého triviální, ale aspoň základy by každý znát měl. Vždy se pokud možno snažte držet alespoň konstantní počet dotazů na databázi, tj. nedotazovat se v cyklu. Totéž by některé ORM systémy řešily 2 dotazy, první by provedly s limit, pak by interně iterovaly, což stejně děláte, ale vše ostatní by vytáhly na základě $IDtemp pomocí konstrukce where id in (...) pomocí jediného dotazu.
Itran
Profil
Nejspíš to předělám podobně, jak psal juriad. U dotazů bude "pocet_reakci" a "id_posledni_odpovedi". U odpovědí bude uveden i "titulek_dotazu". Tím se zjednodušší dotaz na nejnovější příspěvky a taky při vyhledávání to bude snažší.

Alphard: U toho mého příkladu #7 jsem ještě chtěl po prvním dotazu uložit výsledky do proměnných a pak až udělat druhý dotaz jen na chybějící titulky. Titulky doplnit do proměnných a až pak vše vypsat. Tím by se zrušil ten dotaz v cyklu.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: