trialNerror) MyBatis) 조회 데이터 -> List에 정상적으로 담기지 않는 경우 - NVL() / 그룹함수 조회 & resultMap 사용 시

이지우·2022년 11월 15일
0
  • 사례1) SELECT 쿼리 출력할 때 null 값 변환을 위해 NVL()를 사용하였는데 SQL 실행 결과 시엔 정상적으로 출력되었으나 List에 모든 행이 제대로 담기지 않았다.
    -> 데이터 타입의 문제라 생각해 TO_NUMBER(), CAST() 등의 Oracle 메서드를 사용해보았으나 해결안됨.
    => 어차피 null값이 java 변수에 담기면 각각의 기본값으로 변환되므로 서브쿼리에서 null값을 계산해야하는 경우가 아닌 메인 SELECT절에선 NVL()(그리고 다른 문자함수) 사용 지양하는 걸로.

    • cause) 박스오피스에 해당하는 영화가 API 호출했지만 얻지 못해 출력되지않은 것임을 알게되었다.. tbl_movie 테이블에 없었음.. 예상했던 상기 부분들이 원인 아닐수도..
      -> 일단 LEFT OUTER JOIN tbl_movie m 으로 쿼리 수정하고 호출 API 개선하기로함

      @Data
      public class BoxOfficeWithStarDTO {
      
      	private BoxOfficeVO boxOfficeVO;
      	
      	private String posterUrl;
      	private int prdtYear;
      	private String repNationNm;
      	
      	private double avgStarRating;
      	
      	private double userStarRating;

}

```java
public List<BoxOfficeWithStarDTO> getBoxOfficeWithStarList(@Param("showDate") String showDate, @Param("userid") String userid);
  <resultMap type="com.moviepedia.domain.BoxOfficeWithStarDTO" id="boxOfficeWithStarDTO">
	
		<result property="avgStarRating" column="avgstarrating"/>
		<result property="userStarRating" column="userstarrating"/>
		
		<result property="posterUrl" column="posterurl"/>
		<result property="prdtYear" column="prdtyear"/>
		<result property="repNationNm" column="repnationnm"/>
		

		<association property="boxOfficeVO" javaType="com.moviepedia.domain.BoxOfficeVO">
			<id property="showDate" column="showdate"/>
			<id property="movieCd" column="moviecd"/>
			
			<result property="rank" column="rank"/>
			<result property="movieNm" column="movienm"/>
			<result property="openDt" column="opendt"/>
			<result property="audiCnt" column="audicnt"/>
			<result property="audiAcc" column="audiacc"/>
			<result property="updateDate" column="updatedate"/>

		</association>
	</resultMap>


      <select id="getBoxOfficeWithStarList" resultMap="boxOfficeWithStarDTO">

		SELECT DISTINCT b.rank, b.movieCd, b.movieNm, b.openDt, b.audiAcc, b.showDate
			, m.posterUrl, m.prdtYear, m.repNationNm
<!-- 		    , NVL(ROUND(AVG(s.starRating) OVER(PARTITION BY s.movieCd),1), 0) AS avgStarRating -->
		    , ROUND(AVG(s.starRating) OVER(PARTITION BY s.movieCd),1) AS avgStarRating
		    <!-- ?) NVL(, 0(or 0.0)) 이용 시 List에 제대로 안담김. 몇몇 행만 담김... to_number, cast도 안됨 
		    	=> 반환되는 데이터 타입의 문제 아닐까? 
		    	: 어차피 DTO엔 0.0으로 담기므로 할 필요없음.. -->
		 	<if test="userid neq null"> 
			    , (SELECT ss.starRating FROM tbl_starRating ss WHERE ss.userid = #{userid} AND ss.movieCd = b.movieCd) AS userStarRating
		 	</if>
		FROM tbl_boxOffice b
		JOIN tbl_movie m
		ON (b.movieCd = m.movieCd)
		LEFT OUTER JOIN tbl_starRating s
		ON (b.movieCd = s.movieCd)
		WHERE b.showDate = #{showDate} 
		ORDER BY rank ASC
		 
	</select>

  • 사례2) 사례1)과 같이 SELECT절에 AVG(), COUNT() 등의 그룹함수 포함해 조회 & resultmap(collection, association) 사용 시 List에 제대로 담기지 않음.. 도대체 왜? 사례1)의 코드는 NVL() 미사용시 정상적으로 수행됨...
    -> 그룹 함숨를 조회하지 않았더니 정상적으로 List에 담김
    -> resultMap이 아닌 resultType 사용 시 정상적으로 List에 담김
    => DTO에 VO나 다른 DTO를 변수로 하여 resultMap을 이용하지 말고 VO나 다른 DTO의 필요한 변수만 뽑아 새로운 DTO 생성해 resultType 이용하자..
  @Data
  public class DisplayMovieDTO {

      private MovieVO movieVO;

      private double avgStarRating;
      private double userStarRating;

  }
  @Data
  public class DisplayMovieDTO2 {

      private String movieCd;
      private String movieNm;
      private int prdtYear;
      private String repNationNm;
      private String posterUrl;

      private double avgStarRating;
      private double userStarRating;

  }
      <resultMap type="com.moviepedia.domain.DisplayMovieDTO" id="displayMovieDTO">

          <result property="avgStarRating" column="avgstarrating" />
          <result property="userStarRating" column="userstarrating" />

          <association property="movieVO" javaType="com.moviepedia.domain.MovieVO">

              <id property="movieCd" column="moviecd"/>

              <result property="movieNm" column="movienm"/>
              <result property="movieNmEn" column="movieNmEn"/>
              <result property="prdtYear" column="prdtyear"/>
              <result property="openDt" column="openDt"/>
              <result property="typeNm" column="typeNm"/>
              <result property="prdtStatNm" column="prdtStatNm"/>
              <result property="nationAlt" column="nationAlt"/>
              <result property="genreAlt" column="genreAlt"/>
              <result property="repNationNm" column="repNationNm"/>
              <result property="repGenreNm" column="repGenreNm"/>
              <result property="companyCd" column="companyCd"/>
              <result property="companyNm" column="companyNm"/>
              <result property="directorDetail" column="directorDetail"/>
              <result property="showTm" column="showTm"/>
              <result property="actorDetail" column="actorDetail"/>
              <result property="watchGradeNm" column="watchGradeNm"/>
              <result property="posterUrl" column="posterUrl"/>
              <result property="storyText" column="storyText"/>
              <result property="updateDate" column="updateDate"/>
              <result property="commentCnt" column="commentCnt"/>


          </association>
      </resultMap>


      <select id="getHighStarRatingMovieList" resultType="com.moviepedia.domain.DisplayMovieDTO2" >
          SELECT  ft.movieNm, ft.prdtYear, ft.repNationNm, ft.posterUrl, ft.movieCd
              , ft.avgStarRating
          FROM (
              SELECT  iv.movieCd, iv.movieNm, iv.prdtYear, iv.repNationNm, iv.posterUrl
                  , ROUND(AVG(s.starRating), 1) AS avgStarRating
                  , COUNT(s.starRating) AS cntStarRating 
              FROM (
                  SELECT m.movieCd, m.movieNm, m.prdtYear, m.repNationNm, m.posterUrl
                  FROM tbl_movie m
                  WHERE m.movieCd NOT IN (
                      SELECT movieCd
                      FROM tbl_starRating s
                      WHERE userid = #{userid})
              ) iv 
              INNER JOIN tbl_starRating s
              /* INNER JOIN : 다른 유저들이 평가한 영화 중에서 출력 */ 
              ON (iv.movieCd = s.movieCd)
              GROUP BY iv.movieCd, iv.movieNm, iv.prdtYear, iv.repNationNm, iv.posterUrl
              ORDER BY avgStarRating DESC, cntStarRating DESC
          ) ft
          WHERE ROWNUM BETWEEN 1 AND 20	


      </select>
profile
IT개발 입문합니다.

0개의 댓글