我正在使用rails 3.0和MySql 5.1
我有这三种模式:
问题,标签和问题标签。
Tag有一个名为name的列。
问题通过QuestionTags有很多标签,反之亦然。
假设我有 n 标签名称。如何找到仅具有所有 n 标记的问题,这些标记由标记名称标识。
如何在单个查询中执行此操作。
(如果你能说服我在多个查询中做到这一点是最佳的,我会对此持开放态度)
纯粹的rails 3解决方案将是首选,但我也不会对纯SQL解决方案产生负面影响。
请注意,难以进行的查询不会提供包含任何标记的所有问题,而只会提出所有标记的问题
答案 0 :(得分: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
子句中使用子查询是否有所不同。任何见解都将不胜感激。