Kolik řádků splňuje podmínku

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

Pokud chceme zjistit, kolik řádků splňuje nějakou podmínku, můžeme použít jednoduché SELECT COUNT(*) FROM tab WHERE sloupec = hodnota, při požadavku na seskupení potom SELECT skupina, COUNT(*) FROM tab WHERE sloupec = hodnota GROUP BY skupina.

Co však v případě, že nás zajímá i celkový počet řádků nebo třeba poměr řádků, které podmínku splňují? Samozřejmě bychom mohli položit dva dotazy a následně jejich výsledek v kódu spojit, existuje ale elegantnější řešení: SELECT COUNT(*), SUM(IF(sloupec = hodnota, 1, 0)) FROM tab. Výraz SUM(IF(sloupec = hodnota, 1, 0)) přičte jedničku pro každý řádek, který podmínku splňuje. Vzhledem k tomu, že v MySQL je výsledek logických operací vždy 1 nebo 0, dalo by se použít i jednodušší SUM(sloupec = hodnota), vzhledem k nižší čitelnosti bych to ale spíše nedoporučoval.

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

Jakub Vrána, Dobře míněné rady, 16.5.2007, diskuse: 10 (nové: 0)

Diskuse

Postak:

Velmi zajimave a pekne, zajimalo by mne jestli existuje neake reseni pro pripad, kdy bych chtel napriklad tabulku knizek a u nich bych mel sloupec 'pujceno' a chci zjistit kolik mam celkem knizek, kolik jich je pujceno a kolik jeste ne:

SELECT
COUNT(*) AS 'celkem',
SUM(pujceno = 1) AS 'pujceno',
(COUNT(*) - SUM(pujceno = 1)) AS 'nepujceno'
FROM knihy;

Opravdu se musi takto slozite psat dotaz ? Nepocita pote sqlko vse znovu nebo je tak chytre ze jsi to jiz pamatuje ?

Dekuji .]

ikona tiso:

nepujceno nemusíš rátať v dotaze, hádam to vieš odpočítať i v PHP...

Jakub: super finta.

Postak:

ja vim ale jde to jestli jestli muzez tyhle veci resit rovnou v databazi, muzez mit pripady kdy to pote prohanet jeste cyklem (pri group by) je zbytecne..

Rony:

tahle finta je dobra osobne pouzivam misto SUM COUNT a u nej toho ze nezapocitava NULL hodnotu

COUNT(IF(sloupec = hodnota, 1, NULL))

Llaik:

Co kdyz je podminka nad indexovanym sloupcem, pouzije se v tomto pripade index?
Protoze pokud se nepletu, tak v mysql je count(*) extremne rychly, protoze danou informaci bere z hlavicky tabulky a tedy ve skutecnosti nic nepocita.
A nasledny druhy dotaz, ktery provede omezujici podminku pomoci indexu, by byl take vcelku schopny.

Takto na prvni pohled mam strach, ze se index nepouzije a mam sice jen jeden dotaz, ve vysledku ale pomalejsi. Nebo se pletu? :)

ikona Jakub Vrána OpenID:

Tvá obava je oprávněná - index se sice použije, ale jen pro rychlejší přečtení všech dat. Porovnání se potom dělá u každého záznamu zvlášť.

Trik se tedy hodí jen na menší tabulky nebo pro jednorázové operace.

Andrew:

Pěkný Jakubův příklad, ale beru ho spíše jako inspirační, neboť z praxe vím, že mnoho jednoduchých dotazů je podstatně rychlejších než jeden hezký, ale složitý, jak zde poznamenal Llaik.
Nicméně je pěkné vidět, že to pomocí SQL jde a minimálně takový dotaz využiju při přístupu přes konzoli. :-)

PAtrik:

Pekny trik. Napadlo ma ci neexistuje trik aj pre zistenie poctu zaznamov selectu, ktoy ma limit. Teda mam nejaky select s podmienkamy a vysledok chcem listovat, tak vyberiem len 1. stranku, a potrebujem este zistit pocet zaznamov vyhovujuci selectu bez toho limitu. Momentalne to riesim druhym selectom na pocet, ale mozno tu by sa nejaky trik oplatil.

ikona Jakub Vrána OpenID:

Viz http://php.vrana.cz/ziskani-poctu-radek.php.

Pavel:

V případě že budu mít více podmínek existuje i nějaké elegantnější řešení než použít spoustu if podmínek ?

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 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.