9

범위로 확장 할 수 있도록 다음 SQL 쿼리를 ActiveRecord 관계로 변환하는 방법은 무엇입니까?SQL 쿼리를 ActiveRecord 관계로 변환

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 
    ), 

sub_query AS (
    SELECT p.user_id, MAX(weight) as weight 
     FROM joined_table p 
      GROUP BY p.user_id 
), 

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 sub_query 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 

내가 직선적 인 ARel로 시도해야 할 사항입니까?

스코프/하위 쿼리로 분할하려고 시도했지만 하위 쿼리의 선택 항목이 묶는 쿼리에서 끝나며 따라서 열이 그룹의 BY 또는 OR BYER BY에 지정되어 있지 않으므로 PostgreSql 오류가 발생합니다. 성명서.

업데이트 : 귀하는 PostgreSQL이라고 가정합니다. 귀하의 쿼리를 시도했지만 그것은 바로 쿼리와 ActiveRecord 동등 물에 대해 PG::Error: ERROR: column "rownum" does not exist을 던졌습니다.

그러나 별도의 쿼리에서 쿼리를 래핑 할 때 작동합니다. 선택 ROW_NUMBER() 데이터 집합에 투영 될 때까지 만들어지지 않습니다 가정합니다. 나는 다음에 마사지 관리했습니다 어떤

SELECT workouts.*, t.weight, t.workout_set_id, t.exercise_id, t.row_num 
FROM workouts, 
(SELECT workouts.id as workout_id, workout_sets.weight as weight, 
       workout_sets.id AS workout_set_id, 
        workout_exercises.id AS exercise_id, 
        ROW_NUMBER() OVER ( 
      PARTITION BY workouts.user_id 
      ORDER BY workout_sets.weight DESC, workouts.id DESC) row_num 
    FROM workouts 
    JOIN workout_exercises ON workout_exercises.workout_id = workouts.id 
    JOIN workout_sets ON workout_sets.workout_exercise_id = workout_exercises.id) as t 
WHERE workouts.id = t.workout_id AND t.row_num = 1 

:

selected_fields = <<-SELECT 
    workouts.id AS workout_id, 
    workout_sets.weight AS weight, 
    workout_sets.id AS workout_set_id, 
    workout_exercises.id AS exercise_id, 
    ROW_NUMBER() OVER (
     PARTITION BY workouts.user_id 
     ORDER BY workout_sets.weight DESC, workouts.id DESC) as row_num 
    SELECT 

    Workout.joins(", (#{Workout.joins(:workout_exercises => :workout_sets).select(selected_fields).to_sql}) as t").select("workouts.*, t.*").where("workouts.id = t.workout_id AND t.row_num = 1").order("t.weight DESC") 

을하지만 당신이 말할 수있는, 그것은 매우 해키 및 대규모 코드 냄새 그래서 다음 쿼리 작동합니다. 리팩터링하는 방법에 대한 아이디어?

+0

이 쿼리가 사용하는 직접하지 CTE의 ActiveRecord 또는 Arel이 지원합니다. CTE를 피하기 위해이를 리팩토링하면이 중 하나를 사용하여 CTE를 수행 할 수 있습니다. – PinnyM

+0

PostgreSQL을 사용하고 있는지 확인할 수 있습니까? – PinnyM

+0

이 기능도 필요합니다! –

답변

6

당신은 분명히 각 사용자의 가장 높은 무게와 일치하는 최신 운동 (가장 높은 ID) 세부 정보를 얻으려고합니다. 또한 PostgreSQL을 사용하고있는 것으로 보입니다 (MySQL에는 CTE가 없습니다).

그렇다면, 당신은 기능을 윈도를 사용하고 당신의 쿼리를 단순화 할 수 있습니다 : 액티브에 같이 쓸 수있다

SELECT * FROM (
    SELECT workouts.*, workout_sets.weight, 
        workout_sets.id AS workout_set_id, 
        workout_exercises.id AS exercise_id, 
        ROW_NUMBER() OVER (
         PARTITION BY workouts.user_id 
         ORDER BY workout_sets.weight DESC, workouts.id DESC) as rowNum 
    FROM workouts 
    JOIN workout_exercises ON workout_exercises.workout_id = workouts.id 
    JOIN workout_sets ON workout_sets.workout_exercise_id = workout_exercises.id 
) t 
WHERE rowNum = 1 

:

selected_fields = <<-SELECT 
    workouts.*, 
    workout_sets.weight, 
    workout_sets.id AS workout_set_id, 
    workout_exercises.id AS exercise_id, 
    ROW_NUMBER() OVER (
    PARTITION BY workouts.user_id 
    ORDER BY workout_sets.weight DESC, workouts.id DESC) as rowNum 
SELECT 

subquery = Workout.joins(:workout_exercises => :workout_sets). 
        select(selected_fields).to_sql 
Workout.select("*").from(Arel.sql("(#{subquery}) as t")) 
     .where("rowNum = 1") 
+0

Pinny, 원본 질문에 자세한 정보를 추가했습니다. 도와 주셔서 감사합니다. – MunkiPhD

+0

@MunkiPhD : 하위 쿼리가 필요하다는 점에 틀림 없습니다. Arel'from' 및'sql'을 사용하여 업데이트되어 지저분한 상황을 피하십시오. – PinnyM

관련 문제