복붙노트

[SPRING] Spring Data JPA GROUP BY 쿼리에서 커스텀 객체를 반환하는 방법

SPRING

Spring Data JPA GROUP BY 쿼리에서 커스텀 객체를 반환하는 방법

Spring Data JPA로 Spring Boot 애플리케이션을 개발 중입니다. 일부 필드별로 그룹화하고 개수를 얻으려면 사용자 지정 JPQL 쿼리를 사용하고 있습니다. 다음은 내 보관 방법입니다.

@Query(value = "select count(v) as cnt, v.answer from Survey v group by v.answer")
public List<?> findSurveyCount();

작동하며 결과는 다음과 같이 얻어집니다 :

[
  [1, "a1"],
  [2, "a2"]
]

나는 이와 같은 것을 얻고 싶다 :

[
  { "cnt":1, "answer":"a1" },
  { "cnt":2, "answer":"a2" }
]

이것을 어떻게 할 수 있습니까?

해결법

  1. ==============================

    1.이것은 JPA 스펙 내에서 JPQL 조회에 대해 지원됩니다.

    이것은 JPA 스펙 내에서 JPQL 조회에 대해 지원됩니다.

    package com.path.to;
    
    public class SurveyAnswerStatistics {
      private String answer;
      private Long   cnt;
    
      public SurveyAnswerStatistics(String answer, Long cnt) {
        this.answer = answer;
        this.count  = cnt;
      }
    }
    
    public interface SurveyRepository extends CrudRepository<Survey, Long> {
        @Query("SELECT " +
               "    new com.path.to.SurveyAnswerStatistics(v.answer, COUNT(v)) " +
               "FROM " +
               "    Survey v " +
               "GROUP BY " +
               "    v.answer")
        List<SurveyAnswerStatistics> findSurveyCount();
    }
    

    위에서 언급했듯이 new ... 구문은 JPA 지원 메커니즘이며 모든 JPA 공급자와 작동합니다. 그러나 쿼리 자체가 JPA 쿼리가 아닌 경우 (즉, 네이티브 쿼리 인 경우) 새 쿼리 구문이 작동하지 않습니다. 쿼리가 기본 RDBMS로 직접 전달되기 때문입니다. 이후 RDBMS는 새 키워드를 이해하지 못합니다. 이것은 SQL 표준의 일부가 아닙니다.

    이와 같은 상황에서, 빈 클래스는 Spring Data Projection 인터페이스로 대체되어야합니다.

    package com.path.to;
    
    public interface SurveyAnswerStatistics {
      String getAnswer();
    
      int getCnt();
    }
    
    public interface SurveyRepository extends CrudRepository<Survey, Long> {
        @Query(nativeQuery = true, value =
               "SELECT " +
               "    v.answer AS answer, COUNT(v) AS cnt " +
               "FROM " +
               "    Survey v " +
               "GROUP BY " +
               "    v.answer")
        List<SurveyAnswerStatistics> findSurveyCount();
    }
    

    SQL AS 키워드를 사용하여 명확한 맵핑을 위해 결과 필드를 투영 특성에 맵핑하십시오.

  2. ==============================

    2.이 SQL 쿼리는 List 를 반환합니다.

    이 SQL 쿼리는 List 를 반환합니다.

    다음과 같이 할 수 있습니다.

     @RestController
     @RequestMapping("/survey")
     public class SurveyController {
    
       @Autowired
       private SurveyRepository surveyRepository;
    
         @RequestMapping(value = "/find", method =  RequestMethod.GET)
         public Map<Long,String> findSurvey(){
           List<Object[]> result = surveyRepository.findSurveyCount();
           Map<Long,String> map = null;
           if(result != null && !result.isEmpty()){
              map = new HashMap<Long,String>();
              for (Object[] object : result) {
                map.put(((Long)object[0]),object[1]);
              }
           }
         return map;
         }
     }
    
  3. ==============================

    3.저는 이것이 오래된 질문이며 이미 답변을 받았지만 여기에는 또 다른 접근법이 있습니다 :

    저는 이것이 오래된 질문이며 이미 답변을 받았지만 여기에는 또 다른 접근법이 있습니다 :

    @Query("select new map(count(v) as cnt, v.answer) from Survey v group by v.answer")
    public List<?> findSurveyCount();
    
  4. ==============================

    4.커스텀 pojo 클래스 정의하기 sureweQueryAnalytics라고 말하고 커스텀 pojo 클래스에 쿼리 반환 값을 저장한다.

    커스텀 pojo 클래스 정의하기 sureweQueryAnalytics라고 말하고 커스텀 pojo 클래스에 쿼리 반환 값을 저장한다.

    @Query(value = "select new com.xxx.xxx.class.SureveyQueryAnalytics(s.answer, count(sv)) from Survey s group by s.answer")
    List<SureveyQueryAnalytics> calculateSurveyCount();
    
  5. ==============================

    5.나는 쿼리 문자열에 자바 타입 이름을 쓰지 않고 특정 생성자로 처리한다. Spring JPA는 HashMap 매개 변수에서 쿼리 결과를 사용하여 생성자를 암시 적으로 호출합니다.

    나는 쿼리 문자열에 자바 타입 이름을 쓰지 않고 특정 생성자로 처리한다. Spring JPA는 HashMap 매개 변수에서 쿼리 결과를 사용하여 생성자를 암시 적으로 호출합니다.

    @Getter
    public class SurveyAnswerStatistics {
      public static final String PROP_ANSWER = "answer";
      public static final String PROP_CNT = "cnt";
    
      private String answer;
      private Long   cnt;
    
      public SurveyAnswerStatistics(HashMap<String, Object> values) {
        this.answer = (String) values.get(PROP_ANSWER);
        this.count  = (Long) values.get(PROP_CNT);
      }
    }
    
    @Query("SELECT v.answer as "+PROP_ANSWER+", count(v) as "+PROP_CNT+" FROM  Survey v GROUP BY v.answer")
    List<SurveyAnswerStatistics> findSurveyCount();
    

    코드는 @Getter를 해결하기 위해 롬복 필요

  6. from https://stackoverflow.com/questions/36328063/how-to-return-a-custom-object-from-a-spring-data-jpa-group-by-query by cc-by-sa and MIT license