2012-03-07 6 views
3

私は3つのテーブルがあります。これをActiveRecordでより効率的にコーディングする方法はありますか?

  1. ユーザー
  2. 質問
  3. User_Questions

    1.userの質問には、カラムは、私がしたい、question_idをUSER_ID、および

にお答えしました回答されていないランダムな質問を見つけ、は行iを持たないn user_questionsテーブル

すべての質問に回答があった場合は、ランダムな質問を返します。

これはOUTER JOINで行うことができると言われていますが、私はSQLの問題であり、Railsでそれをどうやって行うのか分かりません。
これは私が持っているものです。

def next_question   
    q = Question.all - Question.joins(:user_questions).where 
     (user_questions: { user_id: user_id }) 
    q = Question.all if q.empty? 
    return q[rand(q.size)] 
end 

答えて

1

モデルクラスにallメソッドを呼び出すための十分な理由がほとんどないあります。これにより、そのタイプのデータベース内のすべてのレコードがメモリにロードされます。これが小さなレコードセットであることが絶対にわからない限り、システム全体がハングする可能性があります。それでも、それはのすべてをにロードし、その後、1つのものを選んで残りを捨てることは非常に悪いフォームです。それは、Amazonの各アイテムのうちの1つを注文し、あなたが望むペンを選んで残りの部分をゴミ箱に投じるようなものです。

レコードがランダムに選択されているものがあります。 JOIN

Question.where('id NOT IN (SELECT question_id FROM user_questions WHERE user_id=?)', user_id).order('RAND()').first 

問題は、あなたがuser_questionsテーブルで一致していない逆を持つレコードを検索するつもりだということです。それはおそらく、このようになります。

このクエリは、ユーザーが回答した質問の数が比較的少ないか、またはNOT INが劇的に高価になる可能性があると想定しています。

+1

異なるバージョンのSQLでは、異なるバージョンの 'RANDOM()'が必要なようですが、これはそうです。 – modernserf

1

はい、これに対してLEFT OUTER JOINを使用できます。通常のINNER JOINには結合条件に一致する行のみが含まれ、LEFT JOINには一致する行が含まれ、すべての列にNULLを入れることで適合しない行が抽出されます(PostgreSQL docsは適切な説明があります)。

したがって、LEFT JOINを実行して、NULLを検索することで不一致の行を探します。 SQLは次のように表示されます:

select ... 
from questions 
left outer join user_questions on questions.id = user_questions.question_id 
where user_questions.question_id is null 

これは、あなたには答えられていないすべての質問を与えるでしょう。 ActiveRecordのでは、あなたがこのような何か行うことができます:

Question.joins('left outer join user_questions on question.id = user_questions.question_id') 
     .where(:user_questions => { :question_id => nil }) 
     .limit(1) 

をあなたにもランダムな順序で再生したいかもしれませんが、それはあなたが始める必要があります。それはあなたのマッチを与えるものではありませんなら、あなたはこのようなもので、ランダムな質問をつかむことができます:あなたが大規模なデータベースとの不快なことができるだけでなくQuestions.order('random()').limit(1)しかしORDER BY random()で上記の操作を行うことができ

n = Questions.count 
q = Questions.offset(rand(n)).limit(1) 

。数が非常に速くなければならないので、Rubyでのランダムピッキングをすばやく行うとデータベースが嫌になることはありません。

また、joinsを整理する方法についてはdocumentationをご覧ください。少し標準化されていない構造のデータベースを使用していますので、時には長い道のりが必要です。私がYMMVを綴らない限り、ActiveRecordは私のためにLEFT JOINを拒否しています。

関連する問題