Autor | Zpráva | ||
---|---|---|---|
BunnyBugs Profil * |
#1 · Zasláno: 24. 7. 2015, 15:24:58
Zdravím,
potřeboval bych poradit s následujícím. Potřeboval bych vypsat z DB data, aby vypadala nějak takhle: ![]() V DB mám vytvořeny tyto tabulky a pole (uvádím jen ta důležitá dle obrázku): 1) tabulka akce = id, jmeno, vzdalenost, ... 2) tabulka uzivatele = id, jmeno, ... 3) tabulka prehled = (toto je tabulka spojující ty dvě předchozí, tedy zúčastněné uživatele na jednotlivých akcích) Vůbec nevím, jakým dotazem z DB data vytáhnout a jakým způsobem je pak vypsat do té podoby dle obrázku. Výsledné řazení by mělo být od nejvyššího součtu vzdálenosti, resp. sloupec km. Hledal jsem tady dlouho a hodně toho přečetl, ale mám z toho trochu zamotanou hlavu a potřeboval bych to dostat do co nejjednoduššího tvaru. Předem díky za všechny rady. |
||
Alphard Profil |
#2 · Zasláno: 24. 7. 2015, 15:53:15
Kdyby to mělo být za každou cenu na úrovni databáze (hádám MySQL), hledejte „pivot table“. Ale zvlášť pro tak velký dynamický počet sloupců bych se do toho nepouštěl.
1. Jednodušší varianta s ukládáním do pole Vytáhněte si ta data samostatně (jen ta potřebná) a uložte do pole. Důležité je dát data z tabulky prehled do dvourozměrného pole ve tvaru $summary[$idUser][$idAction] = true (false tam nebude, není ani v databázi).
Výpis pak přes zanořený cyklus foreach ($users as $user) { foreach ($actions a $action) { if (isset($summary[$user->id][$action->id])) { echo $action->distance; } } } 2. složitější varianta bez ukládání Trochu složitější varianta by byla bez ukládání do pole. Data z tabulky prehled by musela být seřazena tak, aby odpovídala výpisu v cyklu (order by user-distance, action-date ) a místo ověřování existence prvku v poli by se kontrolovalo, jestli aktuální prvek ve frontě odpovídá aktuálnímu poli.
// foreach viz výše if ($current->user == $user->id && $current->action == $action->id) { echo $action->distance; $current = $summary->queue->fetch(); } |
||
BunnyBugs Profil * |
#3 · Zasláno: 24. 7. 2015, 18:22:41
Jsem asi natvrdlý, nebo jsem to nějak nepobral :(
Nešlo by ta jednodušší varianta prosím vypsat v kompletním kódu i s výběrem z DB (dosazení do těch proměnných)?, nevím totiž vůbec, kam co dosadit :( Díky moc. |
||
Alphard Profil |
[#3] BunnyBugs
Výběr z databáze psát nebudu, to je jednoduché. Celý algoritmus je jen o tom uvědomit si, jak se jednotlivé buňky skládají. Vytvoříme si akce $actions = [ 0 => ['Akce 1', 100], 1 => ['Akce 2', 50], 2 => ['Akce 3', 70], ]; podobně uživatele $users = [ 0 => ['Hana'], 1 => ['Tereza'], 2 => ['Zuzana'], ]; a na závěr mapu, kdo se účastnil které akce $summary = []; $summary[0][0] = true; // Hana se účastnila všech $summary[0][1] = true; $summary[0][2] = true; $summary[1][0] = true; // Tereza jen první a druhé $summary[1][1] = true; $summary[2][1] = true; // Zuzanadruhé a třetí $summary[2][2] = true; A teď to stačí vypsat // tohle je jen pomůcka pro zarovnání textu na určitou délku, jestli tomu nerozumíte, není to zásadní $length = 8; $formatCell = function($str) use ($length) { return str_pad($str, $length, ' ', STR_PAD_LEFT); }; // Záhlaví tabulky echo '| '.$formatCell('').' | '; foreach ($actions as $action) { echo $formatCell($action[0]); echo ' |'; } echo PHP_EOL; foreach ($users as $idUser => $user) { // Jména uživatelů echo '| '.$formatCell($user[0]).' | '; // Vypsání kartézského součinu do tabulky foreach ($actions as $idAction => $action) { if (isset($summary[$idUser][$idAction])) { echo $formatCell($action[1]); } else { echo $formatCell('-'); } echo ' |'; } echo PHP_EOL; } Výsledek | | Akce 1 | Akce 2 | Akce 3 | | Hana | 100 | 50 | 70 | | Tereza | 100 | 50 | - | | Zuzana | - | 50 | 70 | Já to píši takhle, abych to mohl spouštět v konzoli, vy si zřejmě moji tabulku nahradíte za html. |
||
Časová prodleva: 4 dny
|
|||
BunnyBugs Profil * |
#5 · Zasláno: 28. 7. 2015, 23:18:57
Jsem z toho trochu jelen :( Chápu to tak, že proměnné
$actions, $users, $summary musím vytvořit ručně, nebo to lze vygenerovat příkazem while ?
Něco jako: $vysledek = mysql_query("SELECT `akce`, `jmeno`, `km` FROM `tabulka` WHERE `sezona` = '$vyberSezonu'"); while ($rowvysledek = mysql_fetch_array($vysledek)) { $actions[] = $rowvysledek['akce']; $users[] = $rowvysledek['jmeno']; } $summary
|
||
nightfish Profil |
BunnyBugs:
$actions = array(); $users = array(); $summary = array(); $vysledek = mysql_query("SELECT `akce`, `jmeno`, `km` FROM `tabulka` WHERE `sezona` = '$vyberSezonu'"); while ($row = mysql_fetch_array($vysledek)) { $actions[] = $row['akce']; $users[] = $row['jmeno']; $summary[$row['jmeno']][$row['akce']] = $row['km']; } $actions = array_unique($actions); // aby každá akce byla v poli jenom jednou $users = array_unique($users); // aby každý člověk byl v poli jenom jednou echo "<table>"; echo "<tr><th>Jméno \ Akce</th>"; foreach ($actions as $a) echo "<th>", $a, "</th>"; echo "</tr>"; foreach ($users as $u) { echo "<tr><th>", $u, "</th>"; foreach ($actions as $a) { echo "<td>"; if (isset($summary[$u][$a])) echo $summary[$u][$a]; else echo "-"; echo "</td>"; } echo "</tr>"; } echo "</table>"; |
||
Kcko Profil |
#7 · Zasláno: 31. 7. 2015, 13:36:35
nightfish:
Drobná optimalizace ;-) $actions[$row['akce']] = TRUE ; $users[$row['jmeno']] = TRUE; Pak ten unique nebude potřeba a bude to rychlejší o fous. |
||
Alphard Profil |
Jen pro doplnění, moje původní představa, když jsem psal [#4], bylo použití 3 jednoduchých selectů (s ohledem na http://php.vrana.cz/srovnani-dotazu-do-zavislych-tabulek.php, join není vždy lepší řešení).
Řešení [#6] předpokládá join na úrovni databáze, protože tabulka `tabulka` v této podobě neexistuje (dle [#1], což je podle mě dobrý návrh).
|
||
BunnyBugs Profil * |
#9 · Zasláno: 2. 8. 2015, 13:35:38 · Upravil/a: BunnyBugs
nightfish:
Jojo, takhle je to celkem logické, ale jak v posledním příspěvku píše Alphard, `tabulka` v tomto formátu neexistuje. Mám DB navrhnutou jako N:N, kde `tabulka` je pouze jen spojení jiných tabulek, která obsahuje jen `id_jmeno` z tabulky `uzivatele` , `id_akce` z tabulky `akce` a `km` by mělo být načítáno z tabulky `mista` dle `id_mista` .
Mělo by tedy jít nějak zkombinovat volání tří SELECT , jak uvádí Alphard.
Dle vypsaného kódu podle nightfish bych musel do slučovací tabulky přepisovat údaje z ostatních tabulek, což absolutně ztrácí význam návrhu správné DB, nebo alespoň tak bych to chápal. Abych to zjednodušil a zpřehlednil, tak uvedu jednotlivé tabulky s potřebnými hodnotami: 1) Je pro registrované uživatele s názvem `uzivatele` a pole `id`, `jmeno`, ...
2) Je pro místa akcí s názvem `mista` a pole `id`, `nazev`, `km`, ...
3) Se už vytváří na jednotlivé akce i pomocí tabulky `mista` , její název je `akce` a pole `id`, `id_misto`, `datum_konani`, ...
4) A poslední tabulka je pak závislá na všech, kde jsou pak jednotliví přihlášení k daným akcím s názvem `prehled` a pole `id`, `id_akce`, `id_uzivatel`, ...
A z takto navržené DB bych právě potřeboval dostat výsledek, jak uvádím v příspěvku [#1] BunnyBugs Nevím, jestli mám DB navrženu dobře, ale takhle jsem to ze všelijakých doporučení vyčetl, že by to nějak takhle mělo být. |
||
Alphard Profil |
#10 · Zasláno: 3. 8. 2015, 22:27:18
Moje odpověď [#4] je kompletní a ten kód by měl být spustitelný.
Ty 3 selecty na naplnení polí stačí v té nejjednodušší možné podobě: $actions = []; $actionsSelect = $db->query('select * from actions where sezona = xxx order by yyy'); while ($action = $actionsSelect->fetch()) { $actions[] = $action; } Podobně users a summary takhle:
$summary = []; while ($s = $summarySelect->fetch()) { $summary [$s->idUser][$s->idAction] = true; } |
||
BunnyBugs Profil * |
#11 · Zasláno: 4. 8. 2015, 00:45:31
Alphard:
Asi jsem fakt jouda, nefunguje mi to :( $db->query a ->fetch nefungují, asi jiná databáze, já používám MySQL.
Pokud toto nahradím mysql_query a mysql_fetch_array , vypíše mi to chybu v $sumary ... = true; jako neznámou.
Asi to budu muset dělat pořád ručně, protože to nezmáknu. Funguje mi varianta od nightfish, ale to bych musel zase ty hodnoty nacpat do jedné tabulky a navíc mi to nevrací ten první sloupec, kde bych potřeboval celkový součet km. |
||
Alphard Profil |
#12 · Zasláno: 4. 8. 2015, 11:14:34
BunnyBugs:
Podstatné jsou algoritmy, když používáš jinou knihovnu, neber to doslova. Přepsat to pro mysql extenzi samozřejmě možné je. Nevím, jaká chyba tam vznikla, pojmenování proměnných je třeba uzpůsobit konkrétní situaci. |
||
BunnyBugs Profil * |
#13 · Zasláno: 5. 8. 2015, 02:54:41
Tak jsem to tedy definitivně vyřešil takhle (dle nightfish):
$actions = array(); $users = array(); $summary = array(); $result = mysql_query("SELECT `dat_zapasu`, `jmeno`, `vzdalenost`, `zkratka` ". "FROM `vyjezdy`, `prehled`, `tymy` ". "WHERE vyjezdy.ident = `prehled`.`vyjezd_ident` ". "AND vyjezdy.kdo = tymy.nazev ". "AND vyjezdy.sezona = '2014-15' ". "ORDER BY `dat_zapasu`, `jmeno`"); while ($row = mysql_fetch_array($result)) { $actions[] = $row['dat_zapasu']; $users[] = $row['jmeno']; $summary[$row['jmeno']][$row['dat_zapasu']] = $row['vzdalenost']; } $actions = array_unique($actions); // aby každá akce byla v poli jenom jednou $users = array_unique($users); // aby každý člověk byl v poli jenom jednou echo "<table>"; echo "<tr><th>Jméno \ Akce</th>"; foreach ($actions as $a) echo "<th>", $a , "</th>"; echo "</tr>"; foreach ($users as $u) { echo "<tr><th>", $u, "</th>"; foreach ($actions as $a) { echo "<td>"; if (isset($summary[$u][$a])) echo $summary[$u][$a]; else echo "-"; echo "</td>"; } echo "</tr>"; } echo "</table>"; Je to celé funkční, jen bych potřeboval ještě poradit, jak k tomu přiřadit sloupec se součtem, nejlépe hned za jméno? A pak bych potřeboval doplnit k datu zápasu ještě zkratku týmu, tedy k nadpisům sloupců. Děkuji moc. |
||
BunnyBugs Profil * |
#14 · Zasláno: 6. 8. 2015, 22:14:47
Ještě bych doplnil, že druhý výpis mi generuje celkový součet km a řadí dle jména, kdo má ujeto nejvíce. Tedy takto:
$VyjezdomerTop = mysql_query("SELECT `jmeno`, SUM(`vzdalenost`) AS `soucet` ". "FROM `prehled`, `tymy`, `vyjezdy` ". "WHERE `vyjezdy`.`ident` = `prehled`.`vyjezd_ident` ". "AND `vyjezdy`.`kdo` = `tymy`.`zkratka` ". "AND `vyjezdy`.`sezona` = '$SezonaVyjezdomerTop' ". "AND `vyjezdy`.`dat_zapasu` < '$AktDatum' ". "GROUP BY `jmeno` ". "ORDER BY `soucet` DESC ". "LIMIT 10"); $poradi = $posledni_poradi = 1; $posledni_vzdalenost = null; echo '<table>'. '<tr><th>Poř.</th><th>Jméno/Nick</th><th>km</th></tr>'; while ($rowVyjezdomerTop = mysql_fetch_array($VyjezdomerTop)){ if ($rowVyjezdomerTop['soucet'] !== $posledni_vzdalenost){ $posledni_vzdalenost = $rowVyjezdomerTop['soucet']; $posledni_poradi = $poradi; } echo '<tr><td>'.$posledni_poradi.'</td><td class="left">'.$rowVyjezdomerTop['jmeno'].'</td><td class="right">'.$rowVyjezdomerTop['soucet'].'</td></tr>'; $poradi++; } echo '</table>'; Poradí mi prosím někdo, jak toto spojit do jediného výpisu? případně jestli i mám dobře volené Selecty? Děkuji předem. |
||
BunnyBugs Profil * |
#15 · Zasláno: 7. 8. 2015, 14:08:15
Tak jsem to vyřešil asi takhle:
$actions = array(); $users = array(); $summary = array(); $result = mysql_query("SELECT `dat_zapasu`, `jmeno`, `vzdalenost` ". "FROM `vyjezdy`, `prehled`, `tymy` ". "WHERE vyjezdy.ident = `prehled`.`vyjezd_ident` ". "AND vyjezdy.kdo_zkratka = tymy.zkratka ". "AND vyjezdy.sezona = '$GetVyjezdomerPrehled' ". "AND `vyjezdy`.`dat_zapasu` < '$AktDatum' ". "AND prehled.vyjezdomer = 'ano' ". "ORDER BY `dat_zapasu`, `jmeno`"); while ($row = mysql_fetch_array($result)) { $actions[] = $row['dat_zapasu']; $users[] = $row['jmeno']; $summary[$row['jmeno']][$row['dat_zapasu']] = $row['vzdalenost']; } $actions = array_unique($actions); // aby každá akce byla v poli jenom jednou $users = array_unique($users); // aby každý člověk byl v poli jenom jednou echo "<tr><th>Jméno \ Akce</th><th>Celkem</th>"; foreach ($actions as $a) echo "<th>", date("d.m.", strtotime($a)) , "</th>"; echo "</tr>"; foreach ($users as $u) { $fDB = mysql_query("SELECT `fanklub` FROM `prehled` WHERE `jmeno` = '$u'"); $fCol = mysql_fetch_array($fDB); $f = $fCol['fanklub']; if ($f == "ano"){ echo '<tr><th class="fanklub">', $u, "</th>"; } else { echo '<tr><th>', $u, "</th>"; } echo '<th style="text-align: center;">'; $souDB = mysql_query("SELECT SUM(`vzdalenost`) AS `soucet` ". "FROM `prehled`, `tymy`, `vyjezdy` ". "WHERE `vyjezdy`.`ident` = `prehled`.`vyjezd_ident` ". "AND `vyjezdy`.`kdo_zkratka` = `tymy`.`zkratka` ". "AND `vyjezdy`.`sezona` = '$GetVyjezdomerPrehled' ". "AND `vyjezdy`.`dat_zapasu` < '$AktDatum' ". "AND `jmeno` = '$u' "); $sou = mysql_fetch_array($souDB); echo $sou['soucet']; echo '</th>'; foreach ($actions as $a) { echo "<td>"; if (isset($summary[$u][$a])) { echo $summary[$u][$a]; } else { echo "-"; } echo "</td>"; } echo "</tr>"; } echo "</table>"; Nevím, jestli je to úplně správně, ale funguje to. Resp. řadí se mi to na ose x podle data akce, tj. správně, ale sloupce se mi neřadí podle nejvíce najetých km :( to už nevím, jak na to, zkoušel jsem toho dost, ale vždy to vyhodilo nějakou chybu :( |
||
Časová prodleva: 8 let
|
0