Přehledové tabulky

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

Data jsou v databázi obvykle uložena v podobě jednotlivých hodnot. Jak postupovat, když z nich chceme sestavit přehledovou tabulku, která bude mít v jednotlivých řádcích např. datum a ve sloupcích skupinu? Na webu byste možná našli způsob, jak to udělat v prostém SQL, mnohem jednodušší, přehlednější a obvykle i rychlejší bude z databáze získat základní data a do tabulky je sestavit v PHP:

<?php
// načtení dat do pole array("datum" => array("skupina" => "data"))
$data = array();
$result = mysql_query("SELECT datum, skupina, SUM(cena) AS soucet, COUNT(*) AS pocet FROM tab GROUP BY datum, skupina");
while ($row = mysql_fetch_assoc($result)) {
    $data[$row["datum"]][$row["skupina"]] = "$row[soucet] ($row[pocet])";
}
mysql_free_result($result);

// načtení a vypsání všech skupin
$skupiny = array();
$result = mysql_query("SELECT id, nazev FROM skupiny");
echo "<thead><tr><th></th>";
while ($row = mysql_fetch_assoc($result)) {
    echo "<th>" . htmlspecialchars($row["nazev"]) . "</th>";
    $skupiny[] = $row["id"];
}
echo "</tr></thead>\n";
mysql_free_result($result);

// vypsání všech dat
foreach ($data as $datum => $row) {
    echo "<tr><th>$datum</th>";
    foreach ($skupiny as $skupina) {
        echo "<td>$row[$skupina]</td>";
    }
    echo "</tr>\n";
}
?>

Kód nejprve načte všechna data, potom vypíše skupiny a na závěr i data. Počítá se s tím, že pro každé datum nemusí být záznam u každé skupiny. Pokud bychom chtěli zobrazit údaje jen pro skupiny, které v datech mají záznam alespoň u jednoho dne, naplnili bychom pole $skupiny už při průchodu dat a nechali vypsat názvy jen těchto skupiny: "WHERE id IN (" . implode(", ", array_keys($skupiny)) . ")".

Nevýhoda popsaného řešení spočívá v tom, že je náročné na paměť. Pokud by dat bylo hodně, tak výsledky můžeme na výstup posílat postupně:

<?php
$datum = "";
$result = mysql_query("SELECT datum, skupina, SUM(cena) AS soucet, COUNT(*) AS pocet FROM tab GROUP BY datum, skupina");
while ($row = mysql_fetch_assoc($result)) {
    if ($datum != $row["datum"]) {
        reset($skupiny);
        echo ($datum ? "</tr>\n" : "") . "<tr><th>$row[datum]</th>";
        $datum = $row["datum"];
    }
    while (current($skupiny) != $row["skupina"]) {
        echo "<td></td>";
        next($skupiny);
    }
    echo "<td>$row[soucet] ($row[pocet])</td>";
    next($skupiny);
}
echo ($datum ? "</tr>\n" : "");
mysql_free_result($result);
?>

Kód používá funkce pro získání aktuálního prvku pole current, pro přesun na další prvek next a pro přesun interního ukazatele na začátek pole reset. Kód se spoléhá na to, že v datech nebudou odkazy na neexistující skupiny, protože jinak dojde k zacyklení. Mohlo by nám také vadit, že na konci neúplných řádků nejsou vypsané prázdné buňky tabulky (pokud bychom v tom případě třeba chtěli zobrazit nějakou speciální hodnotu nebo v pravém sloupci celkový součet) – to by se dalo vyřešit doprojitím pole skupin ve větvi $datum != $row["datum"] a po skončení cyklu.

Jakub Vrána, Výuka, 4.5.2007, diskuse: 2 (nové: 0)

Diskuse

symat:

přikla je to pěknej ale pro začatečna uplne na h...o
Kdyby tu byla aspon ukazka je to vypadá! a cele na stažení pro vyskošení na locale

ikona Jakub Vrána OpenID:

Stránky jsou určeny pro mírně pokročilé: http://php.vrana.cz/skladba-ctenaru.php

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.