1

我正在使用 rails 3.0 和 MySql 5.1

我有这三个模型:

问题、标签和问题标签。

Tag 有一个名为 name 的列。

问题通过 QuestionTags 有许多标签,反之亦然。

假设我有n 个标签名称。如何找到具有所有 n 个标签的问题,由标签名称标识。

以及如何在单个查询中执行此操作。

(如果您能说服我在多个查询中执行此操作是最佳的,我将对此持开放态度)

纯 Rails 3 解决方案将是首选,但我也不反对纯 SQL 解决方案。

请注意,困难在于进行查询,它不会给出具有任何标签的所有问题,而只给出具有所有标签的问题。

4

1 回答 1

0

这是我为自己找到的解决方案。未经修改,它只能在 Rails 3(或更高版本)中工作。

在标签模型中:

scope :find_by_names, lambda { |names| 
  unless names.empty?
    where("tags.name IN (#{Array.new(names.length, "?").join(",")})", *names) 
  else
    where("false")
  end
}  

在问题模型中:

scope :tagged_with, lambda { |tag_names| 
  unless tag_names.blank?
    joins(:question_tags).
    where("questions.id = question_tags.question_id").
    joins(:tags).where("tags.id = question_tags.tag_id").
    group("questions.id").
    having("count(questions.id) = ?", tag_names.count) & Tag.find_by_names(tag_names) 
  else
    scoped
  end
}

结合了两个作用域,& Tag.find_by_names(tag_names)使得加入tags实际上是作用域模型上的加入。

[更新]

我的 sql-fu 改进了一点,所以我想我也会提供一个纯 SQL 解决方案:

SELECT q.*
FROM (
SELECT DISTINCT q.*
FROM `questions` q
JOIN question_tags qt
ON qt.question_id = q.id
JOIN tags t
ON t.id = qt.tag_id
WHERE t.name = 'dogs'
) AS q
JOIN question_tags qt
ON qt.question_id = q.id
JOIN tags t
ON t.id = qt.tag_id
WHERE t.name = 'cats'

这会找到所有标记为“猫”和“狗”的问题。这个想法是为我要过滤的每个标签都有一个嵌套的子查询。

还有其他几种方法。我不确定在FROM子句而不是WHERE子句中使用子查询是否会有所不同。任何见解将不胜感激。

于 2010-04-22T07:53:19.843 回答