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 上运行,数据库对查询的 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,您可以选择 distinct 、使用andworkouts嵌套连接、过滤依据和排序依据,如下所示::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 回答