언어/DB 관련

MyBatis 동적 SQL에서 <iterate> 태그로 년도 리스트 처리하기 (에러 해결기)

zumsim 2025. 9. 12. 21:54
728x90
반응형

 

MyBatis 동적 SQL에서 <iterate> 태그로 년도 리스트 처리하기 (에러 해결기)

문제 상황

통계 화면에서 여러 개의 년도를 IN 절에 넣어야 해서 MyBatis <iterate> 태그를 사용했다. 아래처럼 매퍼를 작성하고 실행했는데 에러가 발생했다.

<select id="selectYearStatistics" resultClass="map">
    SELECT YEAR, COUNT(*)
    FROM STATS_TABLE
    WHERE YEAR IN
    <iterate property="yearList" open="(" close=")" conjunction=",">
        #yearList[]#
    </iterate>
</select>
Map<String, Object> param = new HashMap<>();
param.put("yearList", Arrays.asList("2023", "2024"));

실행 시 다음과 같은 에러가 발생했다.

Caused by: java.sql.SQLException: ORA-00907: missing right parenthesis
-- 또는 --
Caused by: java.sql.SQLException: Invalid column index

원인 분석

  • <iterate> 태그 안의 플레이스홀더(#yearList[]#)를 잘못 사용했거나, 콤마 처리가 빠져서 SQL 문법 오류가 발생했다.
  • MyBatis에서 리스트를 바인딩할 때는 conjunction(구분자) 옵션을 써야 한다.
  • 실제 실행된 SQL을 로그로 확인하지 않으면 원인 파악이 어렵다.

해결 방법

코드를 아래처럼 수정했다.

<select id="selectYearStatistics" resultClass="map">
    SELECT YEAR, COUNT(*)
    FROM STATS_TABLE
    WHERE YEAR IN
    <iterate property="yearList" open="(" close=")" conjunction=",">
        #yearList[]#
    </iterate>
</select>

실제 실행된 SQL:

SELECT YEAR, COUNT(*)
FROM STATS_TABLE
WHERE YEAR IN ('2023','2024');

또는 MyBatis 3.x에서는 <foreach> 태그 사용이 권장된다.

<select id="selectYearStatistics" resultType="map">
  SELECT YEAR, COUNT(*)
  FROM STATS_TABLE
  WHERE YEAR IN
  <foreach item="year" collection="yearList" open="(" separator="," close=")">
    #{year}
  </foreach>
</select>

배운 점

동적 리스트 바인딩 시 conjunction / separator 속성을 명시해야 한다. 가능하면 <foreach>를 사용하는 것이 더 안전하고 가독성이 좋다.

728x90
반응형