Při ->group(…)->count(„*“) se volá dotaz bez GROUP BY

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Robyer
Člen | 74
+
+2
-

Používám Nette\Database v aktuálním Nette 2.1.0 s MYSQL databází.

Mám připravené table selection třeba takto:

$res = $db->table("tabulka")->select(...)->group("sloupec");

Když chci spočítat celkový počet řádků pro paginator pomocí ->count("*"), tak se v dotazu „ztratí“ GROUP BY a vrátí se počet všech řádků (vykoná se SELECT COUNT(*) FROM `tabulka`).

Dělám něco špatně nebo je chyba v Nette\Database? Existuje případně workaround jak takový dotaz vykonat správně?


EDIT: Tak zřejmě je to bug:

  1. Buď by to mělo nahradit všechny group() za DISTINCT v selectu a vrátit count takto,
  2. nebo by to mělo vyhodit výjimku, že nad takovým Selection nelze provádět ->count(„*“)
  3. Mělo by to použít poddotaz (viz níže)

V souvislosti s tím pak nefunguje správně ani metoda page() – https://api.nette.org/…ion.php.html#…

Editoval Robyer (28. 1. 2014 9:35)

sKopheK
Člen | 207
+
0
-

Z NDB mi u takových věcí taky občas vstávají vlasy nejen na hlavě, ale věřím že to nějak v NDB řešit jde. Raději bych si ale napsal čistý dotaz, kde máš (větší) jistotu, že to vrátí přesný výsledek.

hrach
Člen | 1838
+
0
-

K cemu ten group by pouzivas? Uved cely konkretni volani.

Robyer
Člen | 74
+
0
-

@hrach Zaznamenávám si vyhledávané fráze na stránkách a pak je chci zobrazit v administraci v tabulce, seskupené dle četnosti jednotlivých hledání.

$items = $this->table("log_search")->select("word, COUNT(*) AS cnt, AVG(results) AS avg")->group("word");

Potom mám v presenteru obecnou metodu, která mi připravuje paginator. Té dám Selection, ze kterého zjistí počet řádků a aplikuje na ni limit.

...
$paginator->itemCount = $items->count("*");
$items->limit($paginator->itemsPerPage, $paginator->offset);
...

Mohl bych si samozřejmě napsat ten dotaz pro získání počtu řádků ručně, ale v tom případě bych očekával, že na mě při volání count(„sloupec“) nad grouped selection vyskočí výjimka (protože takhle se jen tiše vrátí špatný/neočekávaný výsledek).

nanuqcz
Člen | 822
+
0
-

Viz bug, který jsem hlásil víc jak před měsícem.

Robyer
Člen | 74
+
0
-

Pravda, řešení od @nanuqcz se subdotazem je optimální, mé 2 návrhy jsou nesmysl, díky :)

Tedy když bude ->count("*") nad grouped selection, mělo by se to obalit a použít jako subdotaz, např:

SELECT COUNT(*)
FROM (
    SELECT `id`
    FROM `article`
    GROUP BY `article`.`id`
    HAVING `id` > 5
) counted_table

@hrach Co si o tom myslíš?

Robyer
Člen | 74
+
+1
-

Tak pokud by někdo měl stejný problém jako já, může použít tento workaround:

	/**
	 * Workaround for broken count("*") in Nette\Database in grouped selection
	 */
	public function getSelectionCount(\Nette\Database\Table\Selection $items) {
		if ($items->getSqlBuilder()->getGroup()) {
			$query = "SELECT COUNT(*) FROM (" . $items->getSql() . ") AS _";
			$parameters = $items->getSqlBuilder()->getParameters();

			$row = $this->database->queryArgs($query, $parameters)->fetch();
			return $row[0];
		} else {
			return $items->count("*");
		}
	}

Editoval Robyer (28. 1. 2014 9:40)