Nette\Database výpis kategorie s počtem záznamů

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

Zdravím.
Opět jsem pokročil s Nette – je to super framework :-)
Nyní řeším následující problém – dotaz. Mám bazar ve kterém bych chtěl vypsat sekce a počet inzerátů v dané sekci.

DB:

CREATE TABLE IF NOT EXISTS `bazar` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `bazar_category_id` int(11) DEFAULT NULL,
  `date` datetime DEFAULT NULL,
  `title` varchar(100) COLLATE utf8_czech_ci DEFAULT NULL,
  `text` mediumtext COLLATE utf8_czech_ci,
  KEY `id` (`id`,`user_id`,`bazar_category_id`),
  KEY `bazar_category_id` (`bazar_category_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=149 ;

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


ALTER TABLE `bazar`
  ADD CONSTRAINT `bazar_ibfk_3` FOREIGN KEY (`bazar_category_id`) REFERENCES `bazar_category` (`id`),

Chtěl bych vypsat kategorie (tabulka bazar_category) a k nim počet inzerátů v dané kategorii (tabulka bazar )

Ale v praxi dokáži vypsat jen kategoriie:

$this->context->createBazar_category();

Nevěděl by prosím někdo jak v Nette\Database udělat dotaz, který by navíc ještě dokázal spočítat počet záznamů s daným bazar_category_id v tabulce bazar?

Děkuji za jakékoliv nakopnutí a přeji hezký zbytek dne

jtousek
Člen | 951
+
0
-

Jestli jsem někde neudělal chybu tak potřebuješ tenhle dotaz:

SELECT name, COUNT(bazar.id) AS count
FROM bazar_category JOIN bazar ON bazar_category_id = bazar_category.id
GROUP BY bazar_category_id

Bohužel mi uniklo jak donutit Nette\Database udělat JOIN, snad poradí někdo další.

Caine
Člen | 216
+
0
-

V nette\database se join vytváří automaticky, stačí psát jen jaký tabulky se v dotazu použijou (např. bazar.id, resp bazar:id) a v závislosti na použitý reflexi, se sami doplněj joiny. Pro takovej dotaz by mělo stačit následující.

$selection = $connection->table('bazar_category')->select('name')->select('COUNT(bazar:id) AS count')->group('bazar_category_id');
//dvojtecka u bazar:id je backjoin, bazar odkazuje na kategorii,
//pokud by tam byla tecka, snazilo by se to udelat join s tim,
//ze kategorie odkazuje na bazar (coz je blbost).

foreach ($selection as $row) {
	echo $row->name . ': ' . $row->count;
}

//nebo

$selection->fetchPairs('name', 'count'); //vrati [nazev => pocet, ...]

Chvíli trvá, než si na to člověk zvykne, ale je dost navýkový;)

Editoval Caine (8. 5. 2012 10:28)

jtousek
Člen | 951
+
0
-

@Caine: Zajímavé, ale kde jsi zjistil, že to takhle funguje? V dokumentaci to chybí, na fóru taky nikde nic.

James_Scott
Člen | 55
+
0
-

To co nenajdes tady v dokumentaci tak hledej na webu NotORM

Caine
Člen | 216
+
0
-

Tady z forá resp. z videa z poslední soboty (https://forum.nette.org/…ledni-sobote). Ty videa doporučuju, je tam dost věcí, který v dokumentaci pořád chyběj.

motorcb
Člen | 551
+
0
-

Caine napsal(a):

V nette\database se join vytváří automaticky, stačí psát jen jaký tabulky se v dotazu použijou (např. bazar.id, resp bazar:id) a v závislosti na použitý reflexi, se sami doplněj joiny. Pro takovej dotaz by mělo stačit následující.

$selection = $connection->table('bazar_category')->select('name')->select('COUNT(bazar:id) AS count')->group('bazar_category_id');
//dvojtecka u bazar:id je backjoin, bazar odkazuje na kategorii,
//pokud by tam byla tecka, snazilo by se to udelat join s tim,
//ze kategorie odkazuje na bazar (coz je blbost).

foreach ($selection as $row) {
	echo $row->name . ': ' . $row->count;
}

//nebo

$selection->fetchPairs('name', 'count'); //vrati [nazev => pocet, ...]

Chvíli trvá, než si na to člověk zvykne, ale je dost navýkový;)

Díky za info ale co dosadím za $connection ???
S $this->context->table(‚bazar_category‘)->select(‚name‘, ‚href‘)->select(‚COUNT(bazar:id) AS count‘)->group(‚bazar_category_id‘); mi to nefunguje :( Hlásí to:
Call to undefined method SystemContainer::table().

jtousek
Člen | 951
+
0
-

Nemělo by tam být $this->context->connection?

motorcb
Člen | 551
+
0
-

jtousek napsal(a):

Nemělo by tam být $this->context->connection?

Také nejde :(

$this->context->connection->table('bazar_category')->select('name', 'href')->select('COUNT(bazar:id) AS count')->group('bazar_category_id');
Service 'connection' not found.
jtousek
Člen | 951
+
0
-

Tak možná $this->context->database… prostě název služby Nette\Database\Connection, to bys měl vyčíst někde v configu.

motorcb
Člen | 551
+
0
-

jtousek napsal(a):

Tak možná $this->context->database… prostě název služby Nette\Database\Connection, to bys měl vyčíst někde v configu.

Super, tak tohle funguje skvele:

$this->context->database->table('bazar_category')->select('name, href')->select('COUNT(bazar:id) AS count')->group('href')->order('bazar_category.id')

Jen bych ještě potřeboval z toho dotazu získat počet záznamů v tabulce bazar, které nejsou starší než 7 dní (sloupec date). Nevěděl by někdo?
Protože když přidám do dotazu další select a where, tak se where aplikuje na celý dotaz, já bych ho potřeboval aplikovat pouze na zvolenou část :(

$this->context->database->table('bazar_category')->select('name, href')->select('COUNT(bazar:id) AS count')->group('href')->order('bazar_category.id')->select('COUNT(bazar:id) AS countNew')->where()

Díky

vvoody
Člen | 910
+
0
-

motorcb napsal(a):

Jen bych ještě potřeboval z toho dotazu získat počet záznamů v tabulce bazar, které nejsou starší než 7 dní (sloupec date). Nevěděl by někdo?
Protože když přidám do dotazu další select a where, tak se where aplikuje na celý dotaz, já bych ho potřeboval aplikovat pouze na zvolenou část :(

$this->context->database->table('bazar_category')->select('name, href')->select('COUNT(bazar:id) AS count')->group('href')->order('bazar_category.id')->select('COUNT(bazar:id) AS countNew')->where()

Z toho popisu nemam ponatia co presne chces :) ale ked potrebujes polozit odlisny dotaz tak jednoducho zacni od znovu

$this->context->database->table('bazar_category')->....

Ohladne tej podmienky nad stlpcom date, skus toto:

$days = 7;
$date = new DateTime(); //now
$date->sub(new DateInterval('P'.$days.'D')); //now - 7 days

$selection->where('date > ?',$date);
motorcb
Člen | 551
+
0
-

vvoody:
Jde mi o to abych vypsal „Název kategorie ( počet všech příspěvků v kategorii / počet příspěvků za poslední týden)“

Ohladne tej podmienky nad stlpcom date, skus toto:

$days = 7;
$date = new DateTime(); //now
$date->sub(new DateInterval('P'.$days.'D')); //now - 7 days

$selection->where('date > ?',$date);

Kdybych položil samostatný dotaz, jak bych ho spároval z původním dotazem?
Abych k názvu kategorie vypsal správný počet záznamů za poslední týden?

Díky

petr.pavel
Člen | 535
+
0
-

Polož dva dotazy (clone $selection). Mohl bys to sice nějak hackovat přes subquery nebo IF v SQL, ale takhle to bude čistější a nejspíš i rychlejší.

Edit: Dva myslím jako jeden pro celkový počet, druhý pro počet za poslední týden.

Editoval petr.pavel (14. 5. 2012 10:28)

motorcb
Člen | 551
+
0
-

petr.pavel napsal(a):

A jak pak spáruju ty 2 výsledky dotazu v latte? Jak budu vědět jaký záznam přiřadit k názvu kategorie?

petr.pavel
Člen | 535
+
0
-

Přes PHP (ber s rezervou, píšu z hlavy a sám místo NTB používám NotORM):

$vsechny = $this->context->database->table('bazar_category')->select('bazar_category.id, name, href, COUNT(bazar:id) AS pocet')->group('href')->order('bazar_category.id');

$zaTyden = clone $vsechny;
$zaTyden = $zaTyden->where('date > ?',strtotime("-1 week"))->fetchPairs('id', 'pocet');

foreach ($vsechny as $radka) {
  $radka['pocetTyden'] = 0;
  if (isset($zaTyden[ $radka['id'] ])) {
    $radka['pocetTyden'] = $zaTyden[ $radka['id'] ];
  }
}
motorcb
Člen | 551
+
0
-

Tak by pro mne bylo nejlepší to psát přes vložený dotaz.
Dokázal by někdo přepsat tento dotaz do ORM?
Jde to vůbec?

SELECT bc.name, bc.href, bc.id, COUNT(b.id) AS count, ( select count(*) from bazar b2 where bc.id = b2.bazar_category_id and date > 123456789 ) as countNew
FROM bazar_category bc
LEFT JOIN bazar b ON bc.id = b.bazar_category_id
GROUP BY href
ORDER BY bc.id
jtousek
Člen | 951
+
0
-

Tyhle dotazy už jsou poněkud složitější a docela pochybuju, že ti to nějaké ORM nabídne. Přesně pro tyhle případy ve všech ORM zůstává možnost vlastního SQL dotazu.

motorcb
Člen | 551
+
0
-

A je možné nějakým způsobem v NotORM vykonat komplet svůj SQL dotaz?
Abych nemusel skládat ten vnořený dotaz.
Něco takového:

$vsechny = $this->context->database->mySQL("SELECT bc.name, bc.href, bc.id, COUNT(b.id) AS count ...")

Jde to?

petr.pavel
Člen | 535
+
0
-

@motorcb: Ono se zdá pohodlnější zůstat u starého způsobu uvažování a skládat si dotazy sám, ale uvaž, proč jsi vůbec šel do NTD/NotORM. To's přece mohl zůstat u Dibi.

Doporučoval bych ti přečíst důvody, které měl Jakub Vrána k vytvoření NotORM. Případně srovnání rychlosti. Ostatně, Jakubův blog obsahuje i další články, které by ti mohly objasnit smysl a vnitřní chody NotORM (a tudíž i NTD).