Výpis neduplicitních hodnot z databáze
- ForestCZE
- Člen | 209
Ahoj, mám tuto metodu:
public function getTournamentAchievements(int $team): array
{
return $this->database->getTournamentAchievements()->where('team_id', $team)->fetchAll();
}
Potřebuji aby to nevypisovalo stejné hodnoty. Dle dokumentace se má použít tohle:
$this->database->getTournamentAchievements()->where('team_id', $team)->count("DISTINCT tournament_id")->fetchAll()
to ale vrací počet odlišných hodnot, což nechci, potřebuju ty odlišné hodnoty vrátit.
Pak mě ještě napadlo použít select:
$this->database->getTournamentAchievements()->where('team_id', $team)->select("DISTINCT tournament_id")->fetchAll()
tam je ale zase problém, že to nevytáhne ostatní sloupce a musel bych je vypsat všechny. Jak to má být správně? Děkuji předem za pomoc.
Editoval ForestCZE (2. 2. 2021 17:40)
- uestla
- Backer | 799
Ahoj,
metoda getTournamentAchievements()
ti vrací instanci
Nette\Database\Table\Selection
?
Zní to, jako bys potřeboval GROUP BY
, což se u Selection
zapíše takto:
$this->database->getTournamentAchievements()
->where('team_id', $team)
->group('tournament_id, sloupec_2, sloupec_3, ...')
->fetchAll();
- ForestCZE
- Člen | 209
uestla napsal(a):
Ahoj,
metoda
getTournamentAchievements()
ti vrací instanciNette\Database\Table\Selection
?
Zní to, jako bys potřebovalGROUP BY
, což se u Selection zapíše takto:$this->database->getTournamentAchievements() ->where('team_id', $team) ->group('tournament_id, sloupec_2, sloupec_3, ...') ->fetchAll();
Nejsem si jistý, zda GROUP BY
je to, co potřebuju. Výsledek
zde.
- David Matějka
- Moderator | 6445
imho mysql nepodporuje distinct on
jako třeba postgres, ale jen
distinct na úrovni celého řádku. Takže řešením je použít
to group by
edit:
i když tady je to možná fakt ten případ celého řádku, takže distinct s vyjmenováním všech sloupců to řeší :)
- ForestCZE
- Člen | 209
Nějak to pořád nemohu doladit k dokonalosti.
Mám tuto metodu:
public function getTournamentAchievements(int $team): array
{
return $this->database->getTournamentAchievements()->where('team_id', $team)->select('DISTINCT tournament_id, position, points')->fetchAll();
}
Tabulka vypadá takto.
Potřebuju filtrovat podle sloupce team_id
a vypsat jen první
záznam od každého podle tournament_id
(dle screenu 1. a
3. záznam), proto DISTINCT. Zároveň ale potřebuji
selectnout i id
, abych s tím záznamem mohl pracovat. Jakmile ale
id
přidám do selectu, tak opět vidím všechny záznamy. Jak na
to? Díky.
Editoval ForestCZE (9. 2. 2021 11:17)
- David Matějka
- Moderator | 6445
hm, v tom pripade by se ti hodilo to distinct on. v mysql se to musi hackovat treba takto se subquery
ale pak je jeste otazka, jestli mas spravne navrzenou strukturu databaze. proc je v te tabulce vice zaznamu, kdyz te zajima jen jeden?
- ForestCZE
- Člen | 209
David Matějka napsal(a):
hm, v tom pripade by se ti hodilo to distinct on. v mysql se to musi hackovat treba takto se subquery
ale pak je jeste otazka, jestli mas spravne navrzenou strukturu databaze. proc je v te tabulce vice zaznamu, kdyz te zajima jen jeden?
Protože v tomhle momentu se snažím vypsat úspěchy celého týmu, ale
později budu chtít vypsat úspěchy uživatele na jeho profilu, kde mě budou
zajímat všechny dle user_id
. Je to špatně?
Editoval ForestCZE (9. 2. 2021 11:34)
- David Matějka
- Moderator | 6445
a ty uspechy celeho tymu jsou stejne pro vsechny ty uzivatele? jestli jo, tak bys v tehle tabulce nemel mit ty uzivatele, ale jen team, tournament, points, position. a pak mit spojovaci (m:n) tabulku mezi touhle a uzivatelema
- ForestCZE
- Člen | 209
David Matějka napsal(a):
a ty uspechy celeho tymu jsou stejne pro vsechny ty uzivatele? jestli jo, tak bys v tehle tabulce nemel mit ty uzivatele, ale jen team, tournament, points, position. a pak mit spojovaci (m:n) tabulku mezi touhle a uzivatelema
Nakonec se mi podařilo rozjet GROUP BY
, takže Nette samo
vyselectuje, co potřebuji :)
Nyní však nastane problém, když se snažím přidat stránkování.
Metoda v modelu:
public function getTournamentAchievementsByTeam(int $team): Selection
{
return $this->database->getTournamentAchievements()->where('team_id', $team)->group('tournament_id')->order('id DESC');
}
Presenter:
private $tournamentAchievements;
private $achievementsLastPage = 0;
public function actionTeam($id, $tab, $page = 1): void
{
$this->tournamentAchievements = $this->userManager->getTournamentAchievementsByTeam(intval($id))->page($page, 1, $this->achievementsLastPage);
}
public function renderTeam($id, $tab, $page = 1): void
{
$this->template->tournamentAchievements = $this->tournamentAchievements;
$this->template->id = $id;
$this->template->tab = $tab;
$this->template->page = $page;
$this->template->lastPage = $this->achievementsLastPage;
}
Latte:
{foreach $tournamentAchievements as $tournamentAchievement}
//výpis dat
{/foreach}
// Stránky
{if $page > 1}
<a class="link" n:href="User:team id => $id, tab => $tab, page => 1">První</a>
|
<a class="link" n:href="User:team id => $id, tab => $tab, page => $page-1">Předchozí</a>
|
{/if}
Strana {$page} z {$lastPage == 0 ? 1 : $lastPage}
{if $page < $lastPage}
|
<a class="link" n:href="User:team id => $id, tab => $tab, page => $page+1">Další</a>
|
<a class="link" n:href="User:team id => $id, tab => $tab, page => $lastPage">Poslední</a>
{/if}
V databázi jsou 4 záznamy, z toho se vypíšou dva dle
GROUP BY
. Na test jsem dal, že chci jeden záznam na stránku. To
znamená, že bych měl mít dvě stránky po jednom záznamu. Jenže mně to
ukazuje, že jsou ty stránky 4 jako by to nebralo to GROUP a na dvou
stránkách jsou ty záznamy, které tam mají být a na dalších dvou
stránkách není žádný záznam. Co dělám špatně? Díky.
Editoval ForestCZE (10. 2. 2021 4:39)
- ForestCZE
- Člen | 209
Stále je to nevyřešeno. Pokud se zbavím stránkovacího systému, funguje
to normálně. Ať se na to dívám jakkoliv ze všech stran, nevidím chybu.
Jde tam pouze o jednu metodu page
volanou na
Selection
z DB a o její parametry. Vnitřně řeší vše oproti
původnímu použití objektu Paginator
ve starších verzích
Nette. Netuším, co může být špatně.
Editoval ForestCZE (12. 2. 2021 7:15)
- David Matějka
- Moderator | 6445
Ano, strankovani s query, ktery ma group by fungovat nebude. Jedine treba
pres sub-query, coz myslim pres ndb explorer neudelas.
Problem by vyresila ta uprava databaze, jak jsem navrhoval.
V tournament_achievement budes mit sloupecky id, tournament_id, team_id, position a points a user budes mit v tournament_achievement_user, kde budes mit jen tournament_achievement_id a user_id
- ForestCZE
- Člen | 209
David Matějka napsal(a):
Ano, strankovani s query, ktery ma group by fungovat nebude. Jedine treba pres sub-query, coz myslim pres ndb explorer neudelas.
Problem by vyresila ta uprava databaze, jak jsem navrhoval.V tournament_achievement budes mit sloupecky id, tournament_id, team_id, position a points a user budes mit v tournament_achievement_user, kde budes mit jen tournament_achievement_id a user_id
Až teď rozumím tomu, jak jsi to myslel. Zkusím to a případně ještě napíšu. Díky :)
- ForestCZE
- Člen | 209
@DavidMatějka
Mám teda tabulky tournaments, tournament_achievements a tournament_achievements_users
Vytáhnu si všechny úspěchy toho uživatele
z tabulky tournament_achievements_users
public function getTournamentAchievementsByUser(int $userID): Selection
{
return $this->database->getTournamentAchievementsUsers()->where('user_id', $userID)->order('id DESC');
}
Poté výpis v šabloně… Abych mohl vypsat body a umístění, tak se
odkazuji na tabulku tournament_achievements
podle
sloupce tournament_achievement
{foreach $tournamentUserAchievements as $tournamentUserAchievement}
<tr>
<td>{* Zde potřebuji vypsat název turnaje *}</td>
<td>
{switch $tournamentUserAchievement->ref('tournament_achievements', 'tournament_achievement')->position} {* Reference *}
{case 1}
1. <i class="fas fa-trophy gold"></i>
{case 2}
2. <i class="fas fa-trophy silver"></i>
{case 3}
3. <i class="fas fa-trophy bronz"></i>
{/switch}
</td>
<td>{$tournamentUserAchievement->ref('tournament_achievements', 'tournament_achievement')->points}</td> {* Reference *}
<td>-</td>
</tr>
{/foreach}
Jenom si nejsem jistý, jak to je, když potřebuji vypsat i název turnaje. Jaké je správné řešení?
- Mám se z
tournament_achievements_users
odkázat natournament_achievements
a ztournament_achievements
natournaments
? Pokud ano, jak?
nebo
- Mám do
tournament_achievements_users
přidat sloupec, kde bude id tournamentu a rovnou z této tabulky se odkázat natournaments
?
Editoval ForestCZE (12. 2. 2021 16:14)
- David Matějka
- Moderator | 6445
Mám do tournament_achievements_users přidat sloupec, kde bude id tournamentu a rovnou z této tabulky se odkázat na tournaments?
ne, tim by sis rozbil normalizaci databaze
Mám se z tournament_achievements_users odkázat na tournament_achievements a z tournament_achievements na tournaments? Pokud ano, jak?
v podstate ano, na achievementu zavolas ->ref(...)
,
respektive jen ->tournament
a pokud mas spravne fk, tak se
spojovaci klice a cilova tabulka dohleda. Stejne tak muzes pri spravnych FK
nahradit konstrukci
$tournamentUserAchievement->ref('tournament_achievements', 'tournament_achievement')->position
za
$tournamentUserAchievement->tournament_achievement->position
ALE
bude lepsi, kdyz vubec nebudes selectovat z te tournament_achievements_users, ale pouze ji pouzijes pro filtrovani. zhruba nasledovne
$db->table('tournament_achievements')->where(':tournament_achievements_users.user_id', $userId)