Počet záznamů v kategorii?

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

Zdravím mám tyhle 3 tabulky:

CREATE TABLE `work_categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `work_offers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(150) COLLATE utf8_czech_ci NOT NULL,
  `task_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `task_id` (`task_id`),
  CONSTRAINT `work_offers_ibfk_1` FOREIGN KEY (`task_id`) REFERENCES `work_tasks` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `work_tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(150) COLLATE utf8_czech_ci NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  CONSTRAINT `work_tasks_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `work_users` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `work_tasks_categories` (
  `task_id` int(11) NOT NULL,
  `category_id` int(11) NOT NULL,
  KEY `task_id` (`task_id`),
  KEY `category_id` (`category_id`),
  CONSTRAINT `work_tasks_categories_ibfk_1` FOREIGN KEY (`task_id`) REFERENCES `work_tasks` (`id`),
  CONSTRAINT `work_tasks_categories_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `work_categories` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;

A měl bych z toho dostat tento výpis:
Matematika (10/2)
Čeština (25/13)

kde první číslo je celkový počet úkolů v kategorii a druhé počet úkolů, pro které neexistují nabídky (offers)

Jde to v NDBT?? Díky

Editoval jval (2. 9. 2014 13:55)

hitzoR
Člen | 51
+
0
-

Tohle by ti mělo pomoct ;)

jval
Člen | 36
+
0
-

No pokud dám:

<div n:foreach="$categories as $category">
	{$category->name}
	({$category->related('tasks_categories')->count('*')})
</div>

Tak pro celkkový počet úkolů v kategorii to funguje, pak jsem ještě trochu hledal a našel toto fórum
a tak jsem se snažil to natáhnout podle toho příkladu už v modelu s myšlenkou že to bude v jednom dotazu místo dvou:

public function getAll()
    {
        return $this->db->table($this->pfx.'categories')->select('name')->select('COUNT('.$this->pfx.'tasks_categories.task_id) AS count')->order($this->pfx.'categories.id');
    }

ale to mi vyhodí chybu

No reference found for $work_categories->work_tasks_categories
jval
Člen | 36
+
0
-

Tak už jsem našel proč mi to háže chybu:

public function getAll()
    {
        return $this->db->table($this->pfx.'categories')->select('name')->select('COUNT(:'.$this->pfx.'tasks_categories.task_id) AS count')->order($this->pfx.'categories.id');
    }

Dvojtečka a už to maká

jval
Člen | 36
+
0
-

Tak nakonec jsem vypotil s vypětím všech sil tohle:

return $this
    ->db
    ->table($this->pfx . 'categories')
    ->select('name')
    ->select('COUNT(:' . $this->pfx . 'tasks_categories.task_id) AS total')
    ->select('(SELECT COUNT(*) FROM `' . $this->pfx . 'tasks_categories` WHERE `' . $this->pfx . 'tasks_categories`.`task_id` NOT IN (SELECT `task_id` FROM `' . $this->pfx . 'offers` WHERE `task_id` = `' . $this->pfx . 'tasks_categories`.`task_id`) AND `category_id`= `' . $this->pfx . 'categories`.`id`) AS `free`')
    ->group('id');

Pokud je možnost kratšího zápisu, tak se rád poučím :-D

Editoval jval (3. 9. 2014 8:41)

Kcko
Člen | 469
+
-2
-

jval: Takhle se to ale nedělá. Popírá to princip NDBT.

jval
Člen | 36
+
0
-

Kcko: myslel jsem si to, proto jsem psal, že se rád nechám poučit, protože moje znalosti zatím nestačí na to abych ten subselect přetavil do správné formy pro NDBT.

iguana007
Člen | 970
+
0
-

Kcko napsal(a):

jval: Takhle se to ale nedělá. Popírá to princip NDBT.

@Kcko Já NDBT nikdy nepoužil, takže nemůžu být nápomocen, ale možná by @jval více ocenil, kdyby si mu napsal „jak“ to má udělat, než mu jen napsat, že to dělá špatně ;)

Kcko
Člen | 469
+
0
-

@iguana007
odpověděl si sám

jval
Člen | 36
+
0
-

Aha, čili verze s related v šabloně je lepší?
Ten můj výplod ale generuje pouze jeden SQL dotaz na vše a pokud použiji verzi s related v šabloně, tak budu mít dotazy tři.

Mysteria
Člen | 797
+
0
-

Osobně používám normálně ralated v šabloně. Ano, počet dotazů je sice vyšší, ale zjistil jsem, že tohle nemá cenu řešit, protože ve výsledku jsou i tak méně náročné než jeden velký JOIN přes X tabulek (alespoň v mých případech).

Kcko
Člen | 469
+
0
-

Přesně jak píše @Mysteria
Taky jsem nad tím chvíli přemýšlel. Jsou to defakto konstatní dotazy, jsou rychlé a v mnoha ohledech rychlejší než jeden velký obecný (či jak to nazvat).

A píše se to mnohem snadněji a urychluje to práci.

jval
Člen | 36
+
0
-

Ok, chlapi, přesvědčili jste mě. Jen bych možná chtěl aby related bylo v presenteru a v šabloně už opravdu jen foreach aby kóder šablony nad tím nemusel přemýšlet.
Je to možné? Když jsem zkusil něco takového v presenteru:

	$cats=array();
	$categories=$this->categories->getAll();
	foreach ($categories as $key => $value) {
		$cats[$key]['total']=$value->related('tasks_categories')->count('*');
	}
		$this->template->categories = $cats;

tak dostávám hlášku že ActiveRow je read only. Ale jak tedy do toho objektu $categories dostat proměnnou total v presenteru?
Možná se ptám hloupě, opravdu jsem úplný začátečník co se týká nette.

jval
Člen | 36
+
-1
-

Už to asi vzdám a budu related používat v šablonách. Už jsem našel i údajně funkční řešení ale když jsem ho použil (BasePresenter):

public function beforeRender() {
	$categories=$this->categories->getAll();
    $this->template->categories = array();
	foreach ($categories as $category) {
		$this->template->categories[]=array(
            'category' => $category,
            'total' => $category->related('tasks_categories')->count('*'),
            'free' => 0
            );
	}
}

a latte:

<div n:foreach="$categories as $category">
	{$category->name} {({$category->total}/{$category->free})
</div>

tak zase chybová hláška

Trying to get property of non-object
Kcko
Člen | 469
+
0
-

V tu chvíli to není objekt ale pole … tak k tomu přistupuj jako k poli

{$category["category"]->name} {({$category["total"]}/{$category["free"]})
jval
Člen | 36
+
0
-

Super, děkuji, teď už jen domyslet jak ten subselect

(SELECT COUNT(*) FROM `' . $this->pfx . 'tasks_categories` WHERE `' . $this->pfx . 'tasks_categories`.`task_id` NOT IN (SELECT `task_id` FROM `' . $this->pfx . 'offers` WHERE `task_id` = `' . $this->pfx . 'tasks_categories`.`task_id`) AND `category_id`= `' . $this->pfx . 'categories`.`id`) AS `free`')

přetavit do related, i když nevím nevím, protože někde jsem četl, že NDBT a subselecty moc nekámoší.

Editoval jval (4. 9. 2014 21:07)