lze nějak použít UNION a INTERSECT?

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

Ahoj, mám klasickou vazbu M:N ‚book‘ – ‚book_tag‘ – ‚tag‘.

Prví otázka mimo téma zní: lze získat Selection se všema tagama nějaké knížky? Tedy nechci ‚$bookTags‘ (ze které tagy získám po iterování pomocí ‚$bookTag->tag->text‘), ale rovnou ‚tags‘ (po iterování chci ‚$tag->text‘)

A hlavní otázka zní: Jak vybrat knihy, které mají více tagů? Přes klasický AND to nejde, protože ve spojovací tabulce neexistuje řádek, který by odpovídal více tagům. V prostém SQL bych to řešil INTERSECTEM dvou SELECTŮ na dva tagy. Lze to nějak v Nette\Database?

Díky.

Editoval Šaman (3. 3. 2013 10:03)

enumag
Člen | 2118
+
0
-

ad M:N vazba
Přímo přes related to řešit nelze, ale můžeš udělat tohle:

$connection->table('tag')->where('book_tag:book.id', $book->id);

ad více tagů
Řešení jsem tu už někde viděl. Bylo to myslím nějak takhle:

$tags = array(...);
$connection->table('book')->where('book_tag:tag.name', $tags)->group('book.id', 'COUNT(book_tag:tag.name) = ' . count($tags));
Šaman
Člen | 2635
+
0
-

Díky za rychlou odpověď, ono to funguje, dokonce to vygeneruje jediný dotaz :)
Ale sám bych takovýhle dotaz nesestavil, cítím z toho čáry :D

//Edit: Tak už jsem pochopil jak to, že to funguje, ale chvíli to trvalo. Asi to bude i rychlejší, než ten INTERSECT.
A bez klauzule HAVING to vrátí knihy, které obsahují některý z uvedených tagů, tedy se to tváří jako OR.

Editoval Šaman (3. 3. 2013 10:41)

enumag
Člen | 2118
+
0
-

Když jsem to viděl poprvé, byl jsem na tom podobně. ;-) Teď už mi to připadá celkem normální, stačí vědět jak funguje backjoin, group a having. :-P

Jinak trochu se mi tam nelíbí to count($tags), bylo by lepší použít SqlLiteral a ten count dát jako parametr, což ale zatím nejde.

Editoval enumag (3. 3. 2013 10:40)

castamir
Člen | 629
+
0
-

Jen tak pro zajímavost – co to vyhodí za sql?

Ten zápis v NDB je sice pěkně krátkej, přinejmenším kratší, než kdybych to sepsal v sql sám, ale pro neznalého takových magických zápisů je to opravdu těžké na pochopení.

Šaman
Člen | 2635
+
0
-

Jj, to bylo první, čím se se ten dotaz pokusil vylepšit, ale nefunguje..

Díky, po dnešní noci, kterou jsem věnoval Nette\Database a po vyřešení tohohle konečně umím všechny elementální dotazy, které jsem v SQL uměl už před 15ti lety :)

Šaman
Člen | 2635
+
0
-

@castamir:

<script>
SELECT `book`.`id`, `book`.`title`
FROM `book`
INNER JOIN `book_tag` ON `book`.`id` = `book_tag`.`book_id`
INNER JOIN `tag` ON `book_tag`.`tag_id` = `tag`.`id`
WHERE (`tag`.`text` IN ('historie', 'deník'))
GROUP BY `book`.`id`
HAVING COUNT(`tag`.`text`) = 2
</script>

Dotaz až po WHERE včetně vrátí řádek pro každou knihu, která má daný tag, má-li více tagů, bude na více řádkách.

GROUP BY spojí knihy na více řádkách do jednoho řádku (tedy máme všechny knihy, které mají alespoň jeden tag)

A HAVING omezí výsledek jen na knihy, které mají zadaný počet tagů, tedy byly ve výsledku pro každý tag. (máme knihy které mají všechny zadané tagy)

Editoval Šaman (3. 3. 2013 10:51)

castamir
Člen | 629
+
0
-

@Šaman díky. Pěknej výsledek… lepší, než jsem čekal :D

enumag
Člen | 2118
+
0
-

@castamir: Jojo, NDB je v tomhle hodně silná když se s ní umí. ;-) Jinak většina zde probraného je pokrytá v té staré (ale stále aktuální) hrachově přednášce o NDB. Tu jsi viděl, že? :-)

Šaman
Člen | 2635
+
0
-

Ale už jsem přišel na to, jak to obelhat.. Pokud ve spojovací tabulce existují duplikované záznamy, tak se nám může ve výsledku objevit kniha, která má jen jeden ze zadaných tagů, ale tento řádek je tam dvakrát. Takže je potřeba nastavit UNIQUE a počítat s tím při vkládání nových záznamů.

// @enumag: Viděl, jinak bych se nikdy nenaučil trik se špičatým kloboukem s dvojtečkou.

Editoval Šaman (3. 3. 2013 11:03)

castamir
Člen | 629
+
0
-

@enumag neviděl. V Planette ji nevidím…

ale kamarád google něco našel

Editoval castamir (3. 3. 2013 15:51)

enumag
Člen | 2118
+
0
-

@Šaman: Ano, ten UNIQUE constraint jsem mlčky předpokládal. :-) Považuji jej u všech M:N relačních tabulek za samozřejmost.

@castamir: Tak to se omlouvám že jsem neposlal link rovnou, myslel jsem, že ji znáš. Našel jsi to správně, ty triky se špičatým kloboukem bez ní pochopit opravdu snad ani nelze. ;-)