Můj blog – až 10 % špičkového kódu navíc!

Zajímavý SQL dotaz :)

Datum: 29. 4. 2006 0.00 | Autor: Lukáš | 1152× | Kategorie: MySQL | Komentáře: 2
Dneska jsem si kapánek hrál s chart na italianu tak, abych jedním SQL dotazem zároveň vybral aktuální pořadí hitparády, minulé umístění každého songu, celkový počet týdnů, po které je song v hitparádě, datum posledního záznamu zvukové podoby chart a, pokud již hlasovala, IP adresu návštěvníka, aby nemohl hlasovat znovu.
Pro úplnost dodávám, že mám 3 tabulky. Do jedné (chart_ip) se mi ukládají IP adresy, ze kterých bylo hlasováno. Do druhé (chart_live) se mi ukládá číslo kola chart a datum jejího zvukového záznamu (každé kolo hitparády nemusí mít zvukový záznam). No a ve třetí (chart) mám uloženo samotné pořadí každého kola hitparády s tím, že u každého songu je uvedena jeho pozice pro dané kolo (to znamená, že každý song je tam uložen několikrát - v každém kole znovu).

Po chvilce experimentování se mi vše porařilo všechno nacpat do jednoho SQL dotazu:)


SELECT
chart.id, chart.kolo, chart.pozice, chart.popis, chart.ukazka, chart.release, chart.click, COUNT(chart2.id) AS pocetkol, chart3.pozice AS minule, chart_live.datum, chart_ip.ip
FROM chart
INNER JOIN chart AS chart2 ON chart.popis=chart2.popis
LEFT JOIN chart AS chart3 ON (chart.popis=chart3.popis AND chart3.kolo=chart.kolo-1)
LEFT JOIN chart_live ON chart_live.kolo=chart.kolo
LEFT JOIN chart_ip ON chart_ip.ip='$_SERVER[REMOTE_ADDR]'
GROUP BY chart.id
ORDER BY chart.kolo DESC, chart.pozice
LIMIT 20


Protože je v chart uložen každý song několikrát (podle toho, kolikrát již v chart byl) dá se pomocí COUNT(chart2.id) AS pocetkol a následné podmínce INNER JOIN chart AS chart2 ON chart.popis=chart2.popis krásně vypočítat počet účastí. chart3.pozice AS minule mi vybere minulé umístění daného songu - LEFT JOIN chart AS chart3 ON (chart.popis=chart3.popis AND chart3.kolo=chart.kolo-1 (proto ta "-1"). Oboje musím "jakoby" vybrat z další tabulky, to je řešeno přejmenováním původní tabulky (chart AS chart2 a chart AS chart3), díky kterému si mysql myslí, že opravdu vybírám z další tabulky :). Důležité je GROUP BY chart.id, které zajistí, že se vybrané položky seskupí dle počtu vybraných id z tabulky chart - já jich potřebuji 20 (každé kolo hitparády má 20 příček), což dále zajišťuje LIMIT 20. No a nakonec je třeba ještě vybrat těch správných 20 příček - tedy posledních 20 vložených, takže vybrané položky seřadím dle kola sestupně a ještě dle pozice vzestupně ORDER BY chart.kolo DESC, chart.pozice..
No a výsledkem je taková pěkná hitparáda :).



Hezky jsem ještě vyřešil i ověření, zda již IP adresa hlasovala, nebo ne.

if (isset($click)){

MySQL_Query("INSERT INTO chart_ip VALUES ('', '$_SERVER[REMOTE_ADDR]')");

if(mysql_errno()==0){

MySQL_Query("UPDATE chart SET click = click + 1 WHERE id='$click' AND kolo='$k'");

}

}



Nedělám zbytečný výběr podle IP (SELECT ip FROM chart WHERE ip='$_SERVER[REMOTE_ADDR]'), ale díky tomu, že mám sloupec "ip" nastaven jako unikátní, můžu rovnou vkládat. O zbytek se už postará fce mysql_errno(), která při nulové hodnotě (=vložení do tabulky chart_ip proběhlo v pořádku) přičte u dané písničky jeden hlas.


Líp už to snad optimalizovat nešlo :)



Komentáře:

  1. frettie29. 4. 2006 17.46

    Já si naopak mysolím, že jsi dal zabrat tomu serveru, máš to sice v jednom, ale co je moc je prilis :)



    odpovědět
  2. Lukáš29. 4. 2006 18.05

    Je to rozhodně několikanásobně rychlejší, než tam mít 4 SQL dotazy (vyzkoušeno v praxi na vsevjednom.cz) a je to i logické...



    odpovědět

Přidat nový komentář:




Ochrana proti spamu. Napište prosím číslici pět:
Zaškrtněte prosím tuto kolonku: