Autor | Zpráva | ||
---|---|---|---|
Petr_ Profil * |
#1 · Zasláno: 5. 11. 2013, 07:09:46
Dobrý den,
dejme tomu, že mám klasický případ databáze s články (articles) a jejich tagy (tags). Vztah 1:N realizovaný přes vazební tabulku articles_tags. Jednoduchou strukturu i s pár daty uvádím níže. CREATE TABLE IF NOT EXISTS `articles` ( `id` int(11) NOT NULL AUTO_INCREMENT, `content` text NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=4 ; INSERT INTO `articles` (`id`, `content`) VALUES (1, 'First article...'), (2, 'Second article...'), (3, 'Third article...'); CREATE TABLE IF NOT EXISTS `articles_tags` ( `articles_id` int(11) NOT NULL, `tags_id` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `articles_tags` (`articles_id`, `tags_id`) VALUES (1, 1), (2, 1), (2, 3), (3, 1), (3, 2), (3, 3); CREATE TABLE IF NOT EXISTS `tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=4 ; INSERT INTO `tags` (`id`, `name`) VALUES (1, 'First tag'), (2, 'Second tag'), (3, 'Third tag'); Není problém vybrat články podle určitého (jednoho) tagu třeba tímto způsobem: SELECT * FROM articles JOIN articles_tags ON articles.id=articles_tags.articles_id JOIN tags ON tags.id=articles_tags.tags_id WHERE tags.id = 1 Co kdybych ale chtěl vybrat články, které obsahují třeba přesně 2 (nebo volitelně i více) konkrétní tagy? Tedy chtěl bych vybrat články, které mají tagy zároveň s id 1 a 3. Měly by se vybrat články s id 2 a 3. Jde to nějak jednoduše udělat jedním dotazem? |
||
scheras Profil * |
#2 · Zasláno: 5. 11. 2013, 07:13:57
SELECT * FROM articles JOIN articles_tags ON articles.id=articles_tags.articles_id JOIN tags ON tags.id=articles_tags.tags_id WHERE tags.id = 1 AND tags.id = 3 |
||
Tori Profil |
#3 · Zasláno: 5. 11. 2013, 07:23:48
id se nemůže v jednom řádku rovnat dvěma hodnotám zároveň. Použijte dotaz z Některé časteji řešené dotazy pro MySQL - FAQ » Nalezení položek mající všechny hledané vlastnosti - pokud místo ID tagů máte jen jejich názvy, tak místo
IN(1,2,3) bude poddotaz.
|
||
Petr_ Profil * |
#4 · Zasláno: 5. 11. 2013, 08:02:35
Tori:
Děkuji za nakopnutí. Takže ono to díky tomu HAVING COUNT(DISTINCT tags.id) = 2 dodatečně vyfiltruje na základě toho, že tam existuje stejný počet unikátních iděček. To je teda pěkně "ujeté" řešení :-). SELECT *, GROUP_CONCAT(tags.id) FROM articles JOIN articles_tags ON articles.id=articles_tags.articles_id JOIN tags ON tags.id=articles_tags.tags_id WHERE tags.id IN( 1,3) GROUP BY articles.id HAVING COUNT(DISTINCT tags.id) = 2 Já jsem původně uvažoval s něčím takovýmto: SELECT *, CONCAT(",", GROUP_CONCAT(DISTINCT(tags.id)), ",") AS tagy FROM articles JOIN articles_tags ON articles.id=articles_tags.articles_id JOIN tags ON tags.id=articles_tags.tags_id GROUP BY articles.id HAVING tagy LIKE "%,1,3,%" OR tagy LIKE "%,1,%,3,%" OR tagy LIKE "%,3,1,%" OR tagy LIKE "%,3,%,1,%" |
||
Tori Profil |
#5 · Zasláno: 5. 11. 2013, 08:07:48
Petr:
Ten druhý dotaz by byl o dost pomalejší při větším počtu článků/tagů (jednak taháte všechny články+tagy a taky kvůli 4x LIKE). |
||
Časová prodleva: 10 let
|
0