11

questionsユーザーが投票したかどうかによって、すべてを制限する範囲があります。モデルでは:

scope :answered_by, lambda {|u| joins(:votes).where("votes.user_id = ?", u.id) }
scope :unanswered_by, lambda {|u| joins(:votes).where("votes.user_id != ?", u.id) }

コントローラーでは、次のように呼び出します。

@answered = Question.answered_by(current_user)
@unanswered = Question.unanswered_by(current_user)

unanswered_by スコープが正しくありません。私は基本的に、投票がない場所を見つけたいと思っています。代わりに、現在のユーザーと等しくない投票があるかどうかを調べようとしています。結合が存在しないすべてのレコードを返す方法はありますか?

4

3 に答える 3

21

EXISTS次の式を使用します。

WHERE NOT EXISTS (
   SELECT FROM votes v  -- SELECT list can be empty
   WHERE  v.some_id = base_table.some_id
   AND    v.user_id = ?
   )

違い

... NOT EXISTS()(Ⓔ) とNOT IN()(Ⓘ) の間は 2 つです。

  1. パフォーマンス

    Ⓔの方が一般的に速いです。最初の一致が見つかるとすぐにサブクエリの処理を停止します。マニュアル:

    サブクエリは通常、少なくとも 1 つの行が返されるかどうかを判断するのに十分な時間だけ実行され、完了まで実行されるわけではありません。

    NULLⒾ クエリ プランナーによって最適化することもできますが、処理がより複雑になるため、程度は低くなります。

  2. 正しさ

    サブクエリ式の結果の値の 1 つが の場合NULL、Ⓘ の結果は になりますがNULL、一般的なロジックではTRUE- と Ⓔ が返されTRUEます。マニュアル:

    すべての行ごとの結果が等しくないか null で、少なくとも 1 つの null がある場合、の結果NOT INは null です。

本質的に、(NOT) EXISTSほとんどの場合、より良い選択です。

クエリは次のようになります。

SELECT *
FROM   questions q
WHERE  NOT EXISTS (
    SELECT FROM votes v 
    WHERE  v.question_id = q.id
    AND    v.user_id = ?
    );

ベース クエリで結合しないでください。votesそれは努力を無効にするでしょう。

と のほかにNOT EXISTS、 とNOT INを使用した追加の構文オプションがLEFT JOIN / IS NULLありEXCEPTます。見る:

于 2013-01-10T14:46:37.447 に答える
1

これを試して、うまくいくかどうか教えてください

編集-1

scope :unanswered_questions, lambda { joins('LEFT OUTER JOIN votes ON questions.id = votes.question_id').where('votes.question_id IS NULL') }

編集-2

scope :unanswered_by, lambda {|u| where("questions.id NOT IN (SELECT votes.question_id from votes where votes.user_id = ?)",u.id) }
于 2013-01-10T05:18:16.733 に答える