1

Rails 3.0 と MySql 5.1 を使用しています

私はこれらの3つのモデルを持っています:

質問、タグ、および質問タグ。

タグには 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
}

は、2 つの& 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'

これにより、'cats' と 'dogs' の両方でタグ付けされたすべての質問が検索されます。アイデアは、フィルターしたいタグごとにネストされたサブクエリを持つことです。

これには他にもいくつかの方法があります。FROM句の代わりに句にサブクエリを含めることで違いが生じるかどうかはわかりませんWHERE。任意の洞察をいただければ幸いです。

于 2010-04-22T07:53:19.843 に答える