2011-11-03 6 views
0

Disons que vous avez une table posts et une table de tags, et que les deux sont liés par une table post_tags.Comment faire cela dans mysql ou rails

donc

messages a id/sujet/colonnes du corps

balises a id/nom

post_tags a id/post_id/tag_id

dans les rails la terminologie, j'ai un modèle post qui a beaucoup de Tags à travers AssetTags.

J'essaie d'interroger pour un poste qui a 2 étiquettes spécifiques. donc s'il y a une balise rails et une balise mysql, je veux une requête qui retourne un post qui n'a que ces deux balises.

est-ce logique?

Tout moyen de le faire avec activerecord (j'utilise la logique de recherche) ou mysql?

Répondre

1

Cette instruction SQL renvoie les publications contenant les deux balises.

select 
    p.* 
from 
    posts p 
    ,asset_tags atg1 
    ,asset_tags atg2 
    ,tags t1 
    ,tags t2 
where 
    p.id = atg1.post_id 
and t1.id = atg1.tag_id 
and t1.tag = 'MySQL' 
and p.id = atg2.post_id 
and t2.id = atg2.tag_id 
and t2.tag = 'Rails' 
; 

Comme pour le faire via Active Record, une alternative serait d'interroger pour chacune des étiquettes puis & les tableaux résultant pour obtenir l'intersection des deux.

+0

Vous monsieur, êtes un gentleman, un érudit et un dieu parmi les hommes! J'avais déjà compris la solution en utilisant le & des tableaux, mais le Mysql était ce que je cherchais. Bien joué. – concept47

0

Pour MySQL, bien sûr, vous pouvez obtenir les données

SELECT p.* 
    FROM posts p 
    JOIN post_tags pt 
    ON p.post_id = pt.post_id 
    WHERE pt.tag_id in (tagId1, tagId2) 

Je n'ai pas utilisé Rails ActiveRecord mais j'imagine que ce serait quelque chose le long des lignes de

get('posts'); 
join('post_tags','post_id'); 
where_in('tag_id', array(tagId1, tagId2); 
execute(); 
+0

ce renvoie les résultats qui ont soit tagId1 ou tagid2. Je veux seulement des messages qui contiennent à la fois – concept47

+0

ah oups, lisez-le mal. On dirait que vous avez la bonne solution. génial – dispake

0

Compte tenu de ces modèles:

def Post 
    has_many :asset_tags 
    has_many :tags, :through => :asset_tags 
end 

def AssetTag 
    has_one :post 
    has_one :tag 
end 

def Tag 
    has_many :asset_tags 
    has_many :posts, :through => :asset_tags 
end 

Vous pouvez le faire:

Post.joins(:asset_tags => :tag).where(
    "tags.name in ('?', '?')", 'foo', 'bar') 

Maintenant, cela ne fait rien avec l'association has_many :through - je ne suis pas sûr s'il y a même une API plus lisse qui utilise cela.

+0

cela renvoie des résultats qui ont soit foo ou bar. Je veux seulement des messages qui contiennent à la fois au moins – concept47

+0

@John Bachir Je pense que l'on peut simplement utiliser le nom de "a travers de nombreux" association: Post.joins (: tags). – Ernest

+0

@ concept47 ahh, à droite - je ne pense pas que AR/AREL va vous aller très loin dans ce cas. (le code ne sera pas beaucoup plus joli que juste le faire en striaght SQL) –

0

La réponse de John Bachir peut être modifié pour ...

Post.joins(:asset_tags => :tag) 
    .where("tags.name in ('?')", 'foo') 
    .where("tags.name in ('?')", 'bar') 
+0

n'a pas eu l'occasion de l'essayer car son application Rails 2 ... sera intéressante pour voir si cela fonctionne. – concept47

+0

oh j'avais des rails 3 à l'esprit – iGbanam