J'ai un problème et je ne sais pas quelle est la meilleure solution. Ok, j'ai 2 tables: posts (id, titre), posts_tags (post_id, tag_id). J'ai la tâche suivante: doit sélectionner des messages avec des étiquettes ID par exemple 4, 10 et 11. Pas exactement, la poste pourrait avoir d'autres tags en même temps. Alors, comment je pourrais le faire plus optimisé? Créer une table temporaire dans chaque requête? Ou peut-être une sorte de procédure stockée? À l'avenir, l'utilisateur pourrait demander à un script de sélectionner des messages avec n'importe quel nombre de tags (il peut s'agir de 1 tag ou 10 en même temps) et je dois être sûr que la méthode que je choisirai . Désolé pour mon anglais, Merci pour l'attention.requête many-to-many
Répondre
select id, title
from posts p, tags t
where p.id = t.post_id
and tag_id in (4,10,11) ;
?
Est-ce que cela fonctionne?
select *
from posts
where post.post_id in
(select post_id
from post_tags
where tag_id = 4
and post_id in (select post_id
from post_tags
where tag_id = 10
and post_id in (select post_id
from post_tags
where tag_id = 11)))
Cette solution suppose que (post_id, tag_id) en post_tags est appliquée comme UNIQUE:
SELECT id, title FROM posts
INNER JOIN post_tag ON post_tag.post_id = posts.id
WHERE tag_id IN (4, 6, 10)
GROUP BY id, title
HAVING COUNT(*) = 3
Bien que ce n'est pas une solution pour toutes les combinaisons de balises possibles, il est facile de créer aussi dynamique SQL. Pour changer pour d'autres ensembles de variables, changez la liste IN() pour avoir toutes les variables, et COUNT (*) = pour vérifier le nombre de variables spécifiées. L'avantage de cette solution par rapport à la cascade d'un ensemble de JOINs est qu'il n'est pas nécessaire d'ajouter des JOINs, ou même des termes WHERE supplémentaires, lorsque vous modifiez la requête.
+1 Pour utiliser GROUP BY avec HAVING. – Joop
Vous pouvez effectuer un compromis de stockage de temps en stockant un hachage unidirectionnel des noms de balises de tri triées par ordre alphabétique.
Lorsqu'un message est balisé, exécutez select t.name from tags t inner join post_tags pt where pt.post_id = [ID_of_tagged_post] order by t.name
. Concaténez tous les noms de balises, créez un hachage à l'aide de l'algorithme MD5 et insérez la valeur dans une colonne à côté de votre message (ou dans une autre table jointe par une clé étrangère, si vous préférez). Lorsque vous souhaitez rechercher une combinaison spécifique de variables, il suffit d'exécuter (en rappelant de trier les noms de variables) select from posts p where p.taghash = MD5([concatenated_tag_string])
.
Ce sélectionne tous les messages qui ont tout des étiquettes (4, 10, 11):
select distinct id, title from posts
where exists (
select * from posts_tags
where
post_id = id and
tag_id in (4, 10, 11))
Ou vous pouvez utiliser ceci:
select distinct id, title from posts
join posts_tags on post_id = id
where tag_id in (4, 10, 11)
(Les deux seront optimalisés la de la même façon).
Ce sélectionne tous les messages qui ont tous des balises (4, 10, 11):
select distinct id, title from posts
where not exists (
select * from posts_tags t1
where
t1.tag_id in (4, 10, 11) and
not exists (
select * from posts_tags as t2
where
t1.tag_id = t2.tag_id and
id = t2.post_id))
La liste des balises dans la clause in
est ce qui change de manière dynamique (dans tous les cas).
Mais, cette dernière requête n'est pas vraiment rapide, vous pouvez donc utiliser quelque chose comme ceci:
create temporary table target_tags (tag_id int);
insert into target_tags values(4),(10),(11);
select id, title from posts
join posts_tags on post_id = id
join target_tags on target_tags.tag_id = posts_tags.tag_id
group by id, title
having count(*) = (select count(*) from target_tags);
drop table target_tags;
La partie qui change dynamiquement maintenant dans la deuxième déclaration (l'insert).
Ceci sélectionnera les publications avec 1, 2 ou 3 des étiquettes désirées, pas les trois. Et il serait plus clairement écrit (et s'exécuter plus vite) s'il est exprimé comme un JOIN. –
J'ai ajouté du code pour sélectionner les articles qui ont tous les tags. –
J'ai également ajouté le code de jointure pour le premier cas. Bien que, un optimiseur de requête décent traitera le même que la requête avec la clause exists. –
- 1. Django ManyToMany rejoindre la requête
- 2. HQL: requête Hibernate avec ManyToMany
- 3. django - le filtre de requête sur manytomany est vide
- 4. django manytomany à
- 5. Enregistrer la méthode manytomany
- 6. django manytomany validation
- 7. Interrogation django ManyToMany
- 8. Inverser une relation ManyToMany
- 9. django ManyToMany question filtre
- 10. ManyToMany JPA fetch
- 11. annotations Hibernate @ManyToMany
- 12. hibernate manytomany xdoclet
- 13. comment interroger ManyToMany
- 14. relation ManyToMany avec joinTable
- 15. problème JPA ManyToMany
- 16. bidirectionnelle Enregistrement ManyToMany
- 17. django ManyToMany par l'aide
- 18. ManyToMany supprimer problème
- 19. JPA @ManyToMany d'un seul côté?
- 20. django trier par rapport ManyToMany
- 21. enregistrer django ManyToMany non valide
- 22. JPA/Hibernate: ManyToMany delete relation
- 23. @ManyToMany dans un résumé MappedSuperclass
- 24. NHibernate: ManyToMany mapping auto-référencement
- 25. Hibernate @ManyToMany supprimer la relation
- 26. objet d'économie par rapport ManyToMany
- 27. JPA ManyToMany numéro de référence
- 28. Django ManyToMany, ImageField et upload_to
- 29. @ManyToMany: RevType est seulement ADD
- 30. ManyToMany dans Hibernate sans touches composées
Il pourrait renvoyer des messages avec l'étiquette 4 OU 10 ou 11.Mais j'ai exactement besoin de tous ces trois tags dans un seul article. Le problème est ici :) – user52005