Oracle IN 절 1000개 초과 문제 해결 방법

개요:

문제 상황:

  • 예제 쿼리:
select * from member where id in (1, 2, 3, ...)

  • **오류 메시지:**Cause: java.sql.SQLException: ORA-01795: 목록의 최대 표현식 수는 1000입니다
  • **설명:**Oracle 데이터베이스에서 IN (...) 절을 사용할 때 괄호 안의 값이 1000개를 초과하면 오류가 발생합니다.

해결 방안:

이 문제를 해결하기 위한 세 가지 방법을 소개합니다.

방법 1

  • 'or' 키워드를 사용한 조건문으로 분할
select * from member where member_id=1 or member_id=2 or member_id=3 ...

  • Mybatis 구현
<select id="selectMemberList" resultType="com.Member">
    select * from member
    <where>
        <if test="memberIds != null and memberIds.size gt 0">
            <foreach collection="memberIds" item="memberId" index="idx" open="" close="" separator="or">
                member_id = #{memberId, jdbcType=INTEGER}
            </foreach>
        </if>
    </where>
</select>

  • Mybatis 최적화 버전
<select id="selectMemberList" resultType="com.Member">
    select * from member
    <where>
        <choose>
            <when test="memberIds != null and memberIds.size gt 0 and memberIds.size lt 1000">
                <foreach collection="memberIds" item="memberId" index="idx" open="member_id in(" close=")" separator=",">
                    #{memberId, jdbcType=VARCHAR}
                </foreach>
            </when>
            <when test="memberIds != null and memberIds.size ge 1000">
                <foreach collection="memberIds" item="memberId" index="idx" open="" close="" separator="or">
                    member_id = #{memberId, jdbcType=VARCHAR}
                </foreach>
            </when>
        </choose>
    </where>
</select>

방법 2

  • 여러 IN 조건의 결합으로 분할, 각 IN당 1000개 이하
select * from member where member_id in (1,2,3...) and member_id in (1000,1001,1002...) and ...

  • Mybatis 구현
<select id="selectMemberList" resultType="com.Member">
    select * from member
    <where>
        <if test="memberIds != null and memberIds.size gt 0">
            <foreach collection="memberIds" item="memberId" index="idx" open="member_id in(" close=")" separator=",">
                <if test="idx != 0 and (idx % 999) == 0">
                    #{memberId, jdbcType=INTEGER} ) and member_id in( #{memberName, jdbcType=INTEGER}
                </if>
                <if test="idx == 0 or (idx % 999) != 0">
                    #{memberId, jdbcType=INTEGER}
                </if>
            </foreach>
        </if>
    </where>
</select>

방법 3

  • IN 절에 select '고정값' from dual + union all 서브쿼리 사용
select m.* from member m
where m.member_id in (
    select 1 from dual
    union all
    select 2 from dual
    union all
    select 3 from dual
    ...
)

  • Mybatis 구현
<select id="selectMemberList" resultType="com.Member">
    select * from member
    <where>
        <if test="@Ognl@isNotEmpty(memberIds)">
            member_id in
            <foreach collection="memberIds" item="memberId" index="idx" open="(" separator=" union all " close=")">
                select #{memberId} from dual
            </foreach>
        </if>
    </where>
</select>

  • 최적화 버전 (CTE 사용)
with temp as (
    select 1 as id from dual
    union all
    select 2 as id from dual
    ...
)
select m.* from member m
where m.member_id in (
    select temp.id from temp
)

  • Mybatis 구현
<select id="selectMemberList" resultType="com.Member">
    with temp as
    <foreach collection="memberIds" item="memberId" index="idx" open="(" separator=" union all " close=")">
        select #{memberId} as id from dual
    </foreach>
    select m.* from member m
    where m.member_id in (
        select temp.id from temp
    )
</select>

태그: Oracle Database java MyBatis ora-01795

6월 3일 22:59에 게시됨