
상품 정렬을 MyBatis 동적쿼리를 이용해 구현하는 과정에서
where절에 카테고리 이름으로 조건을 주고 정렬하는 과정에서 오류가 발생하였다.
<select id="getNextPageByCreatedAt" parameterType="Map" resultType="products">
SELECT *
FROM products
<where>
<if test="categoryName != '전체'">
AND category_name = #{categoryName}
</if>
<choose>
<when test="selectFilter == 'newProducts'">
<if test="lastCreatedAt != null and lastId != null">
AND #{lastCreatedAt} > created_at
OR (created_at = #{lastCreatedAt} AND #{lastId} > id)
</if>
</when>
<when test="selectFilter == 'highPrice'">
<if test="lastPrice != null and lastId != null">
AND #{lastPrice} > price
OR (price = #{lastPrice} AND #{lastId} > id)
</if>
</when>
<when test="selectFilter == 'lowPrice'">
<if test="lastPrice != null and lastId != null">
AND price > #{lastPrice}
OR (price = #{lastPrice} AND #{lastId} > id )
</if>
</when>
</choose>
</where>
<choose>
<when test="selectFilter == 'newProducts'">
ORDER BY created_at DESC, id DESC
</when>
<when test="selectFilter == 'highPrice'">
ORDER BY price DESC, id DESC
</when>
<when test="selectFilter == 'lowPrice'">
ORDER BY price ASC, id DESC
</when>
<otherwise>
ORDER BY created_at DESC, id DESC
</otherwise>
</choose>
LIMIT 20
</select>
이 코드로 해당 카테고리 이름을 가진 상품 데이터를 최신순으로 정렬해 조회하려 했으나
이후 다음 limit한 리스트 조회 시 다른 카테고리 이름을 가진 상품 데이터가 같이 조회되었다.
==> Preparing: SELECT * FROM products WHERE category_name = ? AND ? > created_at OR (created_at = ? AND ? > id) ORDER BY created_at DESC, id DESC LIMIT 20
==> Parameters: 반다이(String), 2024-08-31T00:00(LocalDateTime), 2024-08-31T00:00(LocalDateTime), 3365(Integer)
<== Columns: id, category_name, name, price, quantity, image_url, created_at, updated_at
<== Row: 3361, 반다이, 원피스 <b>피규어 반다이</b> 초원피스 스타일링 Film Z 4th 니코로빈, 11550, 1, https://shopping-phinf.pstatic.net/main_8001330/80013306812.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3355, 반다이, 가면라이더 히비키 SH 액션 <b>피규어 반다이</b> 스피리츠 일본 1개, 46870, 6, https://shopping-phinf.pstatic.net/main_4966537/49665371983.20240807193018.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3348, 반다이, (9월 입고) <b>반다이</b> 짱구 가챠 <b>피규어</b> 오쿠루미 베이비 스윙 포대기 맹구 훈이 유리 철수, 20000, 5, https://shopping-phinf.pstatic.net/main_8837236/88372367118.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3342, 반다이, 산리오 캐릭터즈 가챠머신 가샤폰 <b>피규어</b> 가챠 마이멜로디, 4500, 3, https://shopping-phinf.pstatic.net/main_8822505/88225052620.1.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3325, 반다이, <b>반다이</b> <b>반다이</b> 울트라히어로 01 울트라맨 <b>피규어</b>, 12180, 2, https://shopping-phinf.pstatic.net/main_4887145/48871457536.20240702182503.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3318, 반다이, SMP 그렌라간 엔키 2종 <b>피규어 반다이</b>, 80000, 10, https://shopping-phinf.pstatic.net/main_4690639/46906398161.20240407022658.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3304, 반다이, (당일출발) FW 건담 컨버지 피규어 16 GUNDAM CONVERGE 개별 미니<b>피규어 반다이</b>, 5000, 9, https://shopping-phinf.pstatic.net/main_8219812/82198121336.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3277, 반다이, <b>반다이</b> SHF 원피스 몽키 D 루피 기어5 니카 SH <b>피규어</b> 아츠, 109300, 4, https://shopping-phinf.pstatic.net/main_8784029/87840292106.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3272, 반다이, (일본내수용)원피스 피규아츠 제로 샹크스 <b>피규어</b> 카무사리 초격전 아츠제로, 142000, 4, https://shopping-phinf.pstatic.net/main_8823066/88230661024.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3229, 반다이, <b>반다이</b> 다간 선가드 엑스카이저 마이트가인 용자열전 컬렉션 1탄 미니 <b>피규어</b>, 153000, 4, https://shopping-phinf.pstatic.net/main_8354346/83543466125.3.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3176, 반다이, <b>반다이</b> 건담 앙상블 <b>피규어</b> 8탄 건담F91 하이젠슬레이 헤비건 모빌슈트, 34000, 1, https://shopping-phinf.pstatic.net/main_8814265/88142652061.1.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3147, 반다이, SHF 원피스 루피 S.H.Figuarts 오니가시마 습격 <b>반다이</b> 프리미엄, 65000, 7, https://shopping-phinf.pstatic.net/main_8567524/85675241119.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3117, 메가하우스, 쿠로코의 농구 타카오 카즈나리 <b>피규어</b> - <b>메가하우스</b>, 115200, 2, https://shopping-phinf.pstatic.net/main_4225551/42255515930.20240718013208.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3102, 메가하우스, 세일러문 치비문 30주년 룩업 <b>피규어</b>, 49500, 2, https://shopping-phinf.pstatic.net/main_8478918/84789186527.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3037, 메가하우스, Excellent Model Saint Seiya Dragon Shiryu <b>Figure MegaHouse</b> From Japan NIP 311797, 191920, 10, https://shopping-phinf.pstatic.net/main_8837553/88375539029.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3033, 메가하우스, 원피스 와노쿠니 미니 <b>피규어</b> 세트 <b>메가하우스</b> 일본 직구, 80600, 3, https://shopping-phinf.pstatic.net/main_8733420/87334209394.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 3023, 메가하우스, 페이트 그랜드오더 라이더 오지만디아스 <b>피규어 메가하우스</b> 한정판 1/8 스케일 Fate/Grand Order, 265000, 1, https://shopping-phinf.pstatic.net/main_8224903/82249031525.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 2995, 메가하우스, 디지몬 디지코레 미니<b>피규어</b> MIX BOX - <b>메가하우스</b>, 166400, 4, https://shopping-phinf.pstatic.net/main_8386195/83861955260.7.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 2944, 메가하우스, 체인소맨 덴지 룩업 <b>메가하우스</b> <b>피규어</b>, 59000, 1, https://shopping-phinf.pstatic.net/main_8606641/86066410707.1.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Row: 2816, 메가하우스, 25년 1월 발매 원피스 샹크스 룩업 <b>피규어</b> - <b>메가하우스</b>, 73500, 9, https://shopping-phinf.pstatic.net/main_8811282/88112821235.2.jpg, 2024-08-31 00:00:00, 2024-08-31 00:00:00
<== Total: 20
조회 결과를 분석한 결과 카테고리 관련 쿼리문이 제대로 수행되지 않은 것으로 판단했다.
<where>
<if test="categoryName != '전체'">
AND category_name = #{categoryName}
</if>
<choose>
<when test="selectFilter == 'newProducts'">
<if test="lastCreatedAt != null and lastId != null">
AND #{lastCreatedAt} > created_at
OR (created_at = #{lastCreatedAt} AND #{lastId} > id)
</if>
</when>
</choose>
</where>
동적 쿼리를 풀어 써보면
WHERE category_name = '카테고리이름' AND '마지막 생성일' > created_at OR ( created_at = '마지막생성일' AND '마지막ID' > id )이렇게 쿼리가 만들어지는데 이 때 OR 연산자는 AND보다 우선순위가 낮기 때문에
OR 우측에 괄호안에 조건이 true면 카테고리 이름이 같지 않아도 조건이 성립하기 때문에
원치 않는 데이터가 조회된 것이였다.
즉, #{lastCreatedAt} > created_at 또는 (created_at = #{lastCreatedAt} AND #{lastId} > id) 조건만 맞으면, category_name이 다른 값이어도 데이터가 조회될 수 있으므로
OR와 AND의 우선순위를 명확히 하기 위해 OR 부분을 괄호로 묶었다.
<if test="lastCreatedAt != null and lastId != null">
AND ( #{lastCreatedAt} > created_at
OR (created_at = #{lastCreatedAt} AND #{lastId} > id) )
</if>
category_name = #{categoryName}이 먼저 적용되고, 그 후에 괄호 안의 OR 조건이 적용되도록 수정하였다.
AND 와 OR의 우선순위에 따라 원하는 조건이 성립할 수 있도록 조건에 우선순위를 잘 부여하고
이러한 생각을 항상 하면서 코드를 짜도록 노력해야겠다.