2

私はこの複雑なクエリをしばらく作成しようとしてきましたが、ActiveRecord では役に立ちませんでした。workout_set.weight指定されたユーザーとエクササイズで最高のワークアウトを取得し、体重で並べ替えようとしています。

モデルは次のようになります (誤ったフィールドは削除されています)。

Workout
  belongs_to :user
  has_many :workout_exercises

WorkoutExercises
  belongs_to :workout
  belongs_to :exercise
  has_many :workout_sets

WorkoutSet
  belongs_to :workout_exercise
  weight

たとえば、次のデータを使用します (exercise_id が同じであると仮定します)。

Steve:
  Workout 1:
     weight: 500
  Workout 2:
     weight: 400

Mark:
  Workout 1:
     weight: 300
  Workout 2:
     weight: 350

予想される結果セットは次のようになります。

  Steve's Workout 1
  Mark's Workout 2

これは PostgreSql 上にあるため、制約は sqlite や MySql よりも厳しくなっています。

更新: 私は PostgreSql で実行しているため、DB はクエリの order_by セクションでより厳密です。以下は、わかりやすくするためにすべてを書き出した RSpec テストです。

    it 'fetches the workout with the highest weight' do
            workout = create(:workout_with_exercises, user: user)
            workout2 = create(:workout_with_exercises, user: user)

            workout.workout_exercises[0].workout_sets[0].weight = 200
            workout.save
            workout2.workout_exercises[0].workout_sets[0].weight = 100
            workout2.save

            expect(user.workouts.count).to eq 2
            exercise = workout.workout_exercises[0]
            max_workout = Workout.joins(workout_exercises: :workout_sets)
                          .where('workout_exercises.exercise_id = ?', exercise.id)
                          .order('workouts.id, workout_sets.weight DESC')
                          .select("workouts.id, workout_sets.weight")
                          .uniq
            #max_workout = user.workouts.max_weight(workout.workout_exercises[0])

            expect(max_workout).to eq [workout]
          end

これは実際に # 例外をスローします。このクエリを使用してさまざまなことを試しましたが、まだ機能しません。次のクエリ(user.id句を除く)を使用してストレートSQlでそれを実行しようとしましたが、空の結果セットが得られました:

max_workout = Workout.find_by_sql("
      SELECT workouts.* 
      FROM workouts,  
        (SELECT DISTINCT workouts.id AS workout_id, workout_sets.weight AS weight
         FROM workouts 
         INNER JOIN workout_exercises ON workout_exercises.workout_id = workouts.id 
         INNER JOIN workout_sets ON workout_sets.workout_exercise_id = workout_exercises.id 
         WHERE workout_exercises.exercise_id = #{exercise.id}
         ORDER BY workouts.id, workout_sets.weight DESC) AS myquery
      WHERE workouts.id = myquery.workout_id")
4

2 に答える 2

1

エクササイズ インスタンス が与えられた場合、次のように、 と によるネスト結合、によるフィルター、および並べ替えexerciseを選択できます。workouts:workout_exercises:workout_setsexercise_idworkout_sets.weight

Workout.joins(:workout_exercises => :workout_sets).
  where('workout_exercises.exercise_id' => exercise.id).
  order('workout_sets.weight DESC').
  uniq
于 2013-04-28T23:01:42.153 に答える
1

多くの作業とさらに多くの調査の後、これは目的の結果セットを生成したクエリです。

WITH joined_table AS (
    SELECT workout_sets.weight AS weight, 
        workouts.user_id AS user_id, 
        workouts.id AS workout_id, 
        workout_sets.id AS workout_set_id,
        workout_exercises.exercise_id AS exercise_id
    FROM workouts 
    INNER JOIN workout_exercises ON workout_exercises.workout_id = workouts.id 
    INNER JOIN workout_sets ON workout_sets.workout_exercise_id = workout_exercises.id       
    ORDER BY workout_sets.weight DESC
    ),

result_set AS (
    SELECT MAX(x.workout_id) AS workout_id, 
           x.user_id, 
           x.weight, 
           x.workout_set_id, 
           x.exercise_id
    FROM joined_table x
    JOIN (SELECT p.user_id, MAX(weight) as weight
        FROM joined_table p
        GROUP BY p.user_id) y 
    ON y.user_id = x.user_id AND y.weight = x.weight
    GROUP BY x.user_id, x.weight, x.workout_set_id, x.exercise_id
    ORDER BY x.weight DESC)

SELECT workouts.*, 
       result_set.weight, 
       result_set.workout_set_id, 
       result_set.exercise_id
FROM workouts, result_set
WHERE workouts.id = result_set.workout_id 
    AND result_set.exercise_id = 1 -- arbitrary exercise ID
    AND workouts.user_id IN (1,2) -- arbitrary set of user IDs
于 2013-05-01T12:38:41.940 に答える