Sql Rails、ActiveRecord、嵌套模型上具有多个连接的复杂查询
一段时间以来,我一直试图通过ActiveRecord创建这个复杂的查询,但没有任何效果。我正在尝试为指定用户获取具有最高训练设置重量的训练,并根据重量进行训练和订购 模型看起来像是删除了错误的字段:Sql Rails、ActiveRecord、嵌套模型上具有多个连接的复杂查询,sql,ruby-on-rails,postgresql,activerecord,Sql,Ruby On Rails,Postgresql,Activerecord,一段时间以来,我一直试图通过ActiveRecord创建这个复杂的查询,但没有任何效果。我正在尝试为指定用户获取具有最高训练设置重量的训练,并根据重量进行训练和订购 模型看起来像是删除了错误的字段: Workout belongs_to :user has_many :workout_exercises WorkoutExercises belongs_to :workout belongs_to :exercise has_many :workout_sets Work
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
例如,假设使用以下数据,练习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")
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
给定一个练习实例练习,您可以选择不同的训练、使用:workout\u exercises和:workout\u set嵌套联接、按练习\u id过滤以及按训练\u set排序。权重如下:
Workout.joins(:workout_exercises => :workout_sets).
where('workout_exercises.exercise_id' => exercise.id).
order('workout_sets.weight DESC').
uniq
经过大量的工作和研究,这是产生所需结果集的查询:
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")
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
我试过了,但没用。Postgres对顺序要求严格,这使得select语句中的列太多,这意味着默认情况下无法选择ID。我已经用你的建议更新了我的问题。很好的问题示例可供学习。自我回答也很好。我想知道也许训练集的数量和重量可以作为训练的属性。这意味着每一次运动都有一个固定的重量。你失去了改变训练集重量的能力,但是如果你不需要改变它们,它会大大简化你的SQL。