Autor | Zpráva | ||
---|---|---|---|
Prochy Profil |
#1 · Zasláno: 24. 2. 2014, 21:43:05
Dobrý večer,
po dlouhé době jsem tu s dotazem ohledně MySQL, který se mi zatím nepodařilo vyřešit. Mám nějaké data, kde jsou řádky, které potřebuji všechny vybrat a vedle toho spočítat počet řádků. Uvedu na příkladě, mám tento dotaz, který mi vybírá řádky klientů a jejich údaje: SELECT `clients`.`id`, `clients`.`date_reg` as date_reg, `clients`.`surname`, `clients`.`first_name`, `sex_client`.`name`, `clients`.`cell_phone`, `clients`.`phone`, `clients`.`email`, `categorie_client`.`name`, `source_client`.`name`, FROM `clients` JOIN `categorie_client` ON (`categorie_client`.`id`=`clients`.`categorie_client`) JOIN `sex_client` ON (`clients`.`sex_client` = `sex_client`.`id`) JOIN `source_client` ON(`clients`.`source_client` = `source_client`.`id`) WHERE `clients`.`date_reg` BETWEEN 0 AND 20140224 ORDER BY date_reg DESC LIMIT 50 OFFSET 0 A teď bych potřeboval nějaký dotaz, který by mi vypsal do řádku sloupec s celkovým počtem vybíraných řádků. Takže např. pro 15 vyfiltrovaných záznamů bude na každým řádku sloupec s count(id)=15. Snažil jsem se na to přijít, ale bohužel bez úspěchu. Našel jsem nějaký příklad s rollupem, ale nějak se mi to nepodařilo rozhodit. Děkuji za rady |
||
Tori Profil |
Prochy:
A jak pomalé by bylo použít další dotaz se SELECT COUNT(*)? Anebo použít proměnnou? Jinak: SELECT SUM(1) as soucet, další sloupce atd. GROUP BY date_reg, nějaký jedinečný sloupec WITH ROLLUP - nejsem si jistá úplně tím date_reg v GROUP BY. Záměrem je, aby to řadilo podle data a zároveň rozlišilo jednotlivé řádky, bo ORDER BY se nedá použít zároveň s GROUP BY. Zkuste, jestli to bude fungovat.
Ale u všech těchto možností získáte počet výsledků až v posledním řádku dat. Nemůžete použít nějakou std. funkci num_rows pro danou DB? (Předpokládám, že se chcete vyhnout procházení výsledků vícekrát.)
|
||
Prochy Profil |
#3 · Zasláno: 25. 2. 2014, 00:20:11
Tori:
Děkuji za odpověď „bo ORDER BY se nedá použít zároveň s GROUP BY. Zkuste, jestli to bude fungovat.“ Ano, tohle nefunguje, zkoušel jsem to. Je to napsaný dokonce v dokumentaci, že není možné použít tyto dvě funkce dohromady. „(Předpokládám, že se chcete vyhnout procházení výsledků vícekrát.)“ Ano, přesně tak. „A jak pomalé by bylo použít další dotaz se SELECT COUNT(*)? Anebo použít proměnnou?“ Ta proměnná mě nějak nenapadla, bude stačit pravděpodobně výsledná hodnota v posledním řádku. Jinak je nutné aby to bylo vše v tom jednom dotazu, mimo dotaz už to není možné zpracovat, jelikož je využíváno komponenty jednoho Datagridu, kde se zadává dotaz s vyhledávanými daty. A zásah do toho Datagridu by ovlinil další stránky, které ho využívají, což se mi zdá zbytečně komplikované. |
||
Kajman Profil |
Rollup by dokázal dát součet do řádku navíc, ne do sloupce. Mysql nepodporuje with ... select syntaxi, takže to jde asi opravdu jen zopakováním dotazu...
SELECT `clients`.`id`, `clients`.`date_reg` AS date_reg, `clients`.`surname`, `clients`.`first_name`, `sex_client`.`name`, `clients`.`cell_phone`, `clients`.`phone`, `clients`.`email`, `categorie_client`.`name`, `source_client`.`name`, `soucet`.`pocet` AS pocet_vsech, Greatest(Least(`soucet`.`pocet` - 50 * 0, 50), 0) AS pocet_vypsano FROM `clients` JOIN `categorie_client` ON ( `categorie_client`.`id` = `clients`.`categorie_client` ) JOIN `sex_client` ON ( `clients`.`sex_client` = `sex_client`.`id` ) JOIN `source_client` ON( `clients`.`source_client` = `source_client`.`id` ) CROSS JOIN (SELECT Count(*) pocet FROM `clients` JOIN `categorie_client` ON ( `categorie_client`.`id` = `clients`.`categorie_client` ) JOIN `sex_client` ON ( `clients`.`sex_client` = `sex_client`.`id` ) JOIN `source_client` ON( `clients`.`source_client` = `source_client`.`id` ) WHERE `clients`.`date_reg` BETWEEN 0 AND 20140224)AS soucet WHERE `clients`.`date_reg` BETWEEN 0 AND 20140224 ORDER BY date_reg DESC LIMIT 50 offset 0 Osobně bych takovou funkčnost doprogramoval do datagridu. |
||
rafej Profil |
#5 · Zasláno: 25. 2. 2014, 12:31:47
Pokud jsem dobře pochopila, co potřebuješ, hledej v MySQL manuálu COALESCE. Tam je to vysvětleno. Příklad ti nemůžu napsat, protože netuším, u které ze spojovaných tabulek potřebuješ sčítat výsledné řádky.
|
||
Kajman Profil |
#6 · Zasláno: 25. 2. 2014, 13:51:50
rafej:
Coalesce vrátí první nenullovou hodnotu ze zadaných argumentů, to mu opravdu nepomůže. |
||
rafej Profil |
#7 · Zasláno: 25. 2. 2014, 15:31:27
Kajman:
Samo o sobě určitě ne, ale s joinem na poddotaz a sečtením hodnot by to pomoct mohlo. Bohužel se čtyřmi tabulkami tohleto dohromady nedám, abych uvedla příklad. |
||
Kajman Profil |
#8 · Zasláno: 25. 2. 2014, 15:50:36
rafej:
Ale on nesčítá hodnoty řádků (sum) ale zajímá se o počet řádků (count) a ten nemůže být nikdy null. Proto mu opravdu coalesce k ničemu není. |
||
rafej Profil |
Kajman:
Velice jsem to zjednodušila pro jednu tabulku, abych ukázala, co myslím. Dotaz vrátí výpis všech klientů, přidán sloupec počet, který obsahuje na jednom řádku počet vrácených záznamů a na ostatních NULL. Bohužel nevím, jak bez řazení dle sloupce počet určit, který řádek vrátí požadovanou hodnotu, ale s pomocí COALESCE se ostatní řádky sloupce počet nastaví na NULL, takže lze tento platný řádek s hodnotou najít testem na NULL. SELECT `clients`.`id`, `clients`.`surname`, `clients`.`first_name`, COALESCE(p,NULL) as pocet FROM `clients` LEFT JOIN (SELECT `clients`.`id`, count(`clients`.`id`) as `p` FROM `clients`) as `o` ON (`clients`.`id`=`o`.`id`) Pokud to jde ještě nějak líp, a zda to bude řádně fungovat i propojením s ostatními tabulkami, ať si tazatel vyzkouší. Je to jen nástin možného postupu. On musí vědět, zda je to pro něj proveditelné. |
||
Tori Profil |
rafej:
„nevím, jak bez řazení dle sloupce počet určit, který řádek vrátí požadovanou hodnotu“ Dá se vybrat nejsnáze první nebo poslední řádek (např. změnou id na min(id) as id v poddotazu). Jelikož ale poddotaz vrací jen jeden řádek dat a použila jste left join, tak je coalesce zbytečné - NULL bude v ostatních řádcích automaticky.
Btw - je milé tu vidět další ženu. :) |
||
Prochy Profil |
#11 · Zasláno: 25. 2. 2014, 20:58:34
Nakonec jsem si upravil ten datagrid, ale potřeboval bych s tím trochu pomoct. Zavedu vás trochu víc do problematiky. Mám teda ten datagrid (Tabella k Nette Fram.), který mi vykreslí tabulku s daty. Datagrid má možnost ajaxové filtrace. Já potřebuju zobrazovat nad gridem shrnující údaje, který získám z těch tabulkových dat. Např. momentálně ten celkový počet filtrovaných řádků. To jsem vyřešil, to není problém. Ale chci to mít více flexibilní, aby mi to fungovalo i např. na sumu dat, kde je daná podmínka.
Takže definuji si následujícím způsobem ty pole nad dagridem v konstruktoru: 'addFields' =>array('top'=>array( 'style' => "clear:both;width:180px;font-size:12px;font-weight:bold;", array( array('text'=>'Přidat klienta', 'tag' =>'a', 'href'=>$this->link('Client:new'), 'style' => 'text-decoration:none;width:80px;' . 'margin:0;height:17px;padding-top:6px;' ), array('text'=>'Počet: ', 'row'=>'id', 'sqlFunc'=>'count', 'style' => 'width:100px;height:17px;padding-top:6px;', ), ), ) Tohle mi momentálně vykreslí následujicí: Přidat klienta | Počet: count(id) Je to flexibilní, že tam můžu přidat libovolný počet řádků nebo sloupců. Teď bych k tomu rád dodělal možnost přidání dalších podmínek k těm např. filtrujícím. Např. že by mi to zobrazovalo zvlášť počet žen a mužů, takže by část konstruktoru vypadala následovně: 'addFields' =>array('top'=>array( 'style' => "clear:both;width:180px;font-size:12px;font-weight:bold;", array( array('text'=>'Přidat klienta', 'tag' =>'a', 'href'=>$this->link('Client:new'), 'style' => 'text-decoration:none;width:80px;' . 'margin:0;height:17px;padding-top:4px;' ), array('text'=>'Počet mužů: ', 'row'=>'id', 'sqlFunc'=>'count', 'style' => 'width:100px;height:17px;padding-top:5px;', 'where' => 'sex_client.name=="muž"', ), array('text'=>'Počet žen: ', 'row'=>'id', 'sqlFunc'=>'count', 'style' => 'width:100px;height:17px;padding-top:5px;', 'where' => 'sex_client.name=="žena"', ), ), ) Jinak jakmile tam mám data, kde se využívá nějaké funkce, tak si ty data hodim k sobě a pak projdu dané vyfiltrované řádky a s každým řádkem provádim tu funkci, takže např. s každým řádkem inkrementuju proměnnou, která má nastavenou vlastnost count. Dejme tomu, že tahla podmínka pro filtrování by byla poměrně jednoduchá. Ale co kdybych chtěl mít těch podmínek víc? Např. následující podmínka: 'where' => 'method_payment.id=1 || method_payment.id=2 || method payment.id=3', Kdyby bylo možný převést tento text přímo na podmínku, tak by to asi šlo, ale jinak mě nic nenapadá. Ještě mě napadlo to vyřešit nějak např. následovně. 'where' => array('or'=>array(1 => 'method_payment.id', 2=>'method_payment.id', 3=>'method_payment.id',)), Ale toto bych sám asi programátorsky nedal. Programuji občas ve volném čase, takže se nepovažuji za nějaký eso. :-) Tohle mě nějak šikovně nenapadá, jak to vyřešit. Je možné, že to řeším úplně chybně, tak se nebudu zlobit za rady. |
||
rafej Profil |
Co takhle?
'where' => 'method_payment.id IN (1,2,3)' a nebo přímo v kódu 'where' => "$field_name IN ( ".implode( ',',$array_of_numbers).")" |
||
Prochy Profil |
#13 · Zasláno: 27. 2. 2014, 19:01:20
Právěže já to nespracovávám v MySQL, ale až poté v PHP, takže tenhle způsob nepřichází v úvahu. Takže např. pro tuhle podmínku:
array('or'=>array(1 => 'method_payment.id', 2=>'method_payment.id', 3=>'method_payment.id',)), Bych potřeboval sestavit něco takového: if(($row['method_payment.id']==1 || $row['method_payment.id']==2 || $row['method_payment.id']==3)) |
||
Tori Profil |
Prochy:
„Takže definuji si následujícím způsobem ty pole nad dagridem v konstruktoru:“ Ten kód, který jste uvedl v [#11], to je ještě součást Tabelly, anebo to je už vaše vlastní nadstavba / controller? (Nepochopila jsem, jestli se ptáte na správnou syntax k něčemu existujícímu, anebo na názor ohledně kódu, který si teprv píšete.) Nemohl by se např. do where předávat callback, který dostane aktuální pole (příp. i celý řádek) a vrátí true/false? |
||
Časová prodleva: 3 dny
|
|||
Prochy Profil |
#15 · Zasláno: 2. 3. 2014, 20:22:53
Tori:
Je to už nadstavba toho datagridu. „Nemohl by se např. do where předávat callback, který dostane aktuální pole (příp. i celý řádek) a vrátí true/false?“ Bohužel callback funkce mi až tolik moc neříkájí. |
||
Časová prodleva: 10 let
|
0