본문 바로가기
⚙️백엔드 : Backend/DataBase

Raw SQL 쿼리를 Sequelize ORM 쿼리로 바꾸는 방법

by 예옹이 2024. 9. 14.

Raw SQL 쿼리를 활용해 원하는 레코드의 컬럼을 가지고 다양한 평균값을 내려고 했는데
동작이 안되더라고요! 그래서 Sequelize ORM 쿼리를 활용해 함수를 다시 만들었습니다

 

🤔 Sequelize ORM 쿼리를 활용해 만든 함수의 장점
- 간결하다
- 이해가 쉽다
- 유지보수가 쉽다 

 

 

Raw SQL 쿼리를 사용한 코드

async getTeamAvg(team_id) {
  try {
    const result = await db.sequelize.query(
      `SELECT
        AVG(ac.job_requirement_score) AS team_job_req_avg,
        AVG(ac.job_autonomy_score) AS team_job_auto_avg,
        AVG(ac.relationship_conflict_score) AS team_rel_conf_avg,
        AVG(ac.job_instability_score) AS team_job_inst_avg,
        AVG(ac.organization_system_score) AS team_org_sys_avg,
        AVG(ac.compensation_adequate_score) AS team_comp_ade_avg,
        AVG(ac.job_culture_score) AS team_job_cul_avg,
        AVG(ac.total_score) AS team_total_avg
      FROM after_cares ac
      JOIN users u ON ac.consultation_user_id = u.id
      WHERE u.team_id = :team_id
      AND YEAR(ac.examined_on) = YEAR(CURDATE());`,
      {
        replacements: { team_id },
        type: db.sequelize.QueryTypes.SELECT,
        raw: true // Ensure raw data without metadata
      }
    );

    // Return the first result from the array
    return result[0] || {}; // Return an empty object if no result
  } catch (error) {
    console.error("Error in getTeamAvg:", error);
    throw error;
  }
}

 

Sequelize ORM 쿼리를 사용한 코드

async getTeamAvg(team_id, year) {
    const yearBetween = getStartAndEndYearWithoutTime(year);
    try {
      const result = await db.after_cares.findAll({
        attributes: [
          [db.sequelize.fn("AVG", db.sequelize.col("job_requirement_score")), "team_job_req_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("job_autonomy_score")), "team_job_auto_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("relationship_conflict_score")), "team_rel_conf_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("job_instability_score")), "team_job_inst_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("organization_system_score")), "team_org_sys_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("compensation_adequate_score")), "team_comp_ade_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("job_culture_score")), "team_job_cul_avg"],
          [db.sequelize.fn("AVG", db.sequelize.col("total_score")), "team_total_avg"],
        ],
        where: {
          consultation_team_id: team_id,
          examined_on: {
            [Op.between]: [yearBetween.start, yearBetween.end],
          },
        },
        raw: true,
      });
      return result[0] || {};
    } catch (error) {
      console.error("Error in getTeamAvg:", error);
      throw error;
    }
  }

 

 


 

변환하는 방법

예 ) 변환할 Raw SQL 쿼리

SELECT AVG(ac.job_requirement_score) AS team_job_req_avg
FROM after_cares ac
JOIN users u ON ac.consultation_user_id = u.id
WHERE u.team_id = :team_id
AND YEAR(ac.examined_on) = YEAR(CURDATE());

-- 넘겨받은 team_id와 동일한 값을 가진 users 테이블의 사용자가 연결된 after_cares 데이터 중, examined_on의 연도가 현재 연도인 레코드의 job_requirement_score 평균을 계산하는 쿼리

 

 

Raw SQL 쿼리 변환하는 과정 (Step-by-Step)

(1) SELECT 구문을 attributes로 변환

SELECT에서 계산할 필드는 Sequelize에서 attributes 속성을 사용하여 지정한다
예를 들어, AVG(ac.job_requirement_score) 같은 SQL 구문은 sequelize.fn 함수를 사용하여 정의

attributes: [
  [sequelize.fn('AVG', sequelize.col('job_requirement_score')), 'team_job_req_avg']
]

 

(2) JOIN 구문을 include로 변환

Sequelize ORM에서는 테이블을 조인할 때 include 옵션을 사용한다
JOIN users u ON ac.consultation_user_id = u.id 구문은 다음과 같이 변환

include: [{
  model: Users,
  where: { team_id: team_id },  // 조인 조건
  attributes: [],  // users 테이블에서 필요한 속성들
}]

 

(3) WHERE 절을 where 옵션으로 변환

WHERE 구문은 where 옵션으로 정의한다
특히 YEAR(CURDATE())와 같은 날짜 필터링은 Sequelize의 Op 연산자를 사용하여 처리할 수 있다

where: {
  examined_on: {
    [Op.between]: [startYear, endYear],  // 년도를 특정 범위로 필터링
  },
},

 

(4) 최종 코드

async function getTeamAvg(team_id) {
  const year = new Date().getFullYear();
  const { start, end } = getStartAndEndYearWithoutTime(year); // util에 있는 특정 년도의 시작과 끝 범위를 반환해주는 함수

  try {
    const result = await AfterCares.findAll({
      attributes: [
        [sequelize.fn('AVG', sequelize.col('job_requirement_score')), 'team_job_req_avg']
      ],
      include: [{
        model: Users,
        where: { team_id: team_id },  // 조인 조건
        attributes: [],
      }],
      where: {
        examined_on: {
          [Op.between]: [start, end],  // 날짜 범위 필터링
        },
      },
      raw: true,
    });

    return result;
  } catch (error) {
    console.error("Error in getTeamAvg:", error);
    throw error;
  }
}