【问题标题】:How do you do this in mysql or rails你如何在mysql或rails中做到这一点
【发布时间】:2011-11-03 07:06:57
【问题描述】:

假设您有一个posts 表和一个tags 表,两者都通过一个post_tags 表关联。

所以

帖子有 id/subject/body 列

标签有 id/name

post_tags 有 id/post_id/tag_id

在 Rails 术语中,我有一个 Post 模型,它通过 AssetTags 包含许多标签。

我正在尝试查询具有 2 个特定标签的帖子。 所以如果有一个rails标签和一个mysql标签,我想要一个返回只有这两个标签的帖子的查询。

有意义吗?

有什么方法可以用 activerecord(我正在使用搜索逻辑)或 mysql 来做到这一点?

【问题讨论】:

    标签: mysql ruby-on-rails ruby activerecord searchlogic


    【解决方案1】:

    此 SQL 返回包含两个标签的帖子。

    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'
    ;
    

    至于通过 Active Record 进行,另一种方法是查询每个标签,然后 & 得到的数组得到两者的交集。

    【讨论】:

    • 先生,您是绅士、学者和人中的神!我已经想出了使用数组的 & 的解决方案,但 Mysql 正是我正在寻找的。干得好。
    【解决方案2】:

    对于mysql,当然可以获取数据

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

    我没有使用过 Rails ActiveRecord,但我想它会类似于

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

    【讨论】:

    • 这将返回具有 tagId1 或 tagid2 的结果。我只想要至少包含两者的帖子
    • 啊哎呀,读错了。看起来你得到了正确的解决方案。真棒
    【解决方案3】:

    鉴于这些模型:

    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
    

    你可以这样做:

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

    现在,这实际上与 has_many :through 关联没有任何作用——我不确定是否提供了一个更流畅的 api 来利用它。

    【讨论】:

    • 这将返回具有 foo 或 bar 的结果。我只想要至少包含两者的帖子
    • @John Bachir 我认为可以使用“通过许多”关联的名称:Post.joins(:tags)。
    • @concept47 啊,是的——我认为在这种情况下 AR/AREL 不会让你走得太远。 (代码不会比直接用 SQL 编写更漂亮)
    【解决方案4】:

    John Bachir 的答案可以修改为...

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

    【讨论】:

    • 没有尝试这个,因为它是一个 Rails 2 应用程序......看看它是否有效会很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 2014-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多