我一直试图创建这个复杂的查询一段时间,但无法通过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
实际上会引发#异常。我已经尝试过这个查询的一堆东西,但仍然无法让它工作。我最终尝试使用以下查询在直接SQl中执行此操作(不包括user.id子句),但我得到一个空结果集:
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")
答案 0 :(得分:1)
给定一个练习实例exercise
,您可以选择不同的workouts
,嵌套加入:workout_exercises
和:workout_sets
,过滤exercise_id
,然后按{排序{1}}如下:
workout_sets.weight
答案 1 :(得分: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