Setřídění záznamů podle vlastního kritéria

Školení, která pořádám

Článek vyšel v rámci PHP okénka na serveru Root.cz.

Řekněme, že chceme uživateli na stránce elektronického obchodu zobrazit posledních pět výrobků, které si prohlížel. Pro uložení takovéto informace se ideálně hodí session proměnná:

<?php
// $id je ID právě prohlíženého záznamu
if (!isset($_SESSION["prohlednute"])) {
    $_SESSION["prohlednute"] = array(); // prvotní inicializace pole
} elseif (($pos = array_search($id, $_SESSION["prohlednute"])) !== false) { // $id už v poli je
    unset($_SESSION["prohlednute"][$pos]); // vyjmeme ho a později vložíme na konec
} else {
    unset($_SESSION["prohlednute"][4]); // zobrazovat pouze posledních 5 prohlédnutých výrobků
}
// na tomto místě bude výpis prohlédnutých záznamů
array_unshift($_SESSION["prohlednute"], $id); // uložíme aktuální zboží pro příští stránku
?>

Výpis prohlednutých záznamů by byl triviální za předpokladu, že bychom zboží nechtěli řadit podle pořadí, ve kterém bylo prohlédnuté. Pokud ho tak ale řadit chceme, budeme se muset trochu snažit:

<?php
if ($_SESSION["prohlednute"]) {
    $vyrobky = array();
    $result = mysql_query("SELECT * FROM vyrobky WHERE id IN (" . implode(", ", $_SESSION["prohlednute"]) . ")");
    while ($row = mysql_fetch_assoc($result)) {
        $vyrobky[$row["id"]] = $row;
    }
    mysql_free_result($result);
    foreach ($_SESSION["prohlednute"] as $id) {
        // zobrazení záznamu $vyrobky[$id]
    }
}
?>

Kód je ale neelegantní a náročný na paměť. Problém se dá mnohem elegantněji vyřešit s využitím MySQL funkce FIELD. Tato funkce přijímá seznam parametrů a vrací pořadí prvního z nich mezi ostatními. Např. FIELD(id, 2, 4, 6) tedy vrátí pro id=4 dvojku, protože 4 je mezi dalšími parametry na druhém místě. A to je přesně ta funkce, kterou potřebujeme – výsledek chceme setřídit podle pořadí id v poli $_SESSION["prohlednute"].

<?php
if ($_SESSION["prohlednute"]) {
    $prohlednute_list = implode(", ", $_SESSION["prohlednute"]);
    $result = mysql_query("SELECT * FROM vyrobky WHERE id IN ($prohlednute_list) ORDER BY FIELD(id, $prohlednute_list)");
    while ($row = mysql_fetch_assoc($result)) {
        // zobrazení záznamu $row
    }
    mysql_free_result($result);
}
?>

Třídění podle dynamického výrazu je ještě pomalejší než třídění podle neindexovaného sloupce, takže bychom se mu za normálních okolností měli vyhnout. Na tomto místě si ho ale můžeme dovolit, protože počet vrácených záznamů je pevně omezen.

Přijďte si o tomto tématu popovídat na školení Návrh a používání MySQL databáze.

Jakub Vrána, Řešení problému, 27.6.2005, diskuse: 7 (nové: 0)

Diskuse

pif:

ahoj jakube :) jsem po dlouhe dobe zavital, i kdyz nevim jestli si vzpomenu a zajdu tady do komentu i na odpoved...

muzes mi zodpovedet, proc jsi pouzil array_search a proc treba ne in_array? :)

ikona spaze:

poradne jsem to nestudoval, ale in_array() vraci T/F, kdezto array_search() vraci i pozici. Ale mozna je trick i nekde jinde ;)

ikona Jakub Vrána OpenID:

To je jednoduché, klíč prvku v poli se následně potřebuje, proto se rovnou uloží do proměnné $pos.

derhaa:

ahoj, jakube - psal si článek na třídění záznamů z tabulky v určitém počtu s tím, že je možné je procházet (stránkovat) - nemohu to najít...:(

ikona Jakub Vrána OpenID:

Co třeba http://php.vrana.cz/hledat.php?search=str…%C3%A1n%C3%AD?

Mike:

Při použití ORDER BY FIELD jsem se setkal s problémem. Pokud zadám do MyPHPAdmina dotaz s využitím ORDER BY FIELD, vše proběhne bez problémů, pokud tentýž dotaz použiji v PHP, neprovede se a skončí hláškou "FUNCTION mojedb.FIELD does not exist". Nechápu. Na NETu jsem žádné řešení nenašel, jen podobný problém zde: http://www.dbforums.com/mysql/1213534-order-…#post4531759
Čím to může být? Nějaké nastavení v PHP, když v SQL to chodí?
Na localhostu mi totéž chodí bez problémů, takže tipuji na něco na webhostingu.

Díky za pomoc

Mike:

Tak už jsem na to přišel, tak jen postřeh pro ostatní: mezi FIELD a levou závorkou NESMÍ být mezera. Zajímavé je, že třeba u "WHERE ID IN (" to nevadí.

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.