Estoy desarrollando una aplicación Spring Boot con Spring Data JPA. Estoy usando una consulta JPQL personalizada para agrupar por algún campo y obtener el conteo. A continuación está mi método de repository.
@Query(value = "select count(v) as cnt, v.answer from Survey v group by v.answer") public List findSurveyCount();
Está funcionando y el resultado se obtiene de la siguiente manera:
[ [1, "a1"], [2, "a2"] ]
Me gustaría obtener algo como esto:
[ { "cnt":1, "answer":"a1" }, { "cnt":2, "answer":"a2" } ]
¿Cómo puedo conseguir esto?
Esto es compatible con consultas JPQL dentro de la especificación JPA .
Paso 1 : declara una clase de bean simple
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; } }
Paso 2 : Devolver las instancias de beans desde el método de repository
public interface SurveyRepository extends CrudRepository { @Query("SELECT " + " new com.path.to.SurveyAnswerStatistics(v.answer, COUNT(v)) " + "FROM " + " Survey v " + "GROUP BY " + " v.answer") List findSurveyCount(); }
MyBean
y está en el paquete com.path.to
, la ruta completa al bean será com.path.to.MyBean
. Simplemente proporcionar MyBean
no funcionará (a menos que la clase de bean esté en el paquete predeterminado). new
palabra clave. SELECT new com.path.to.MyBean(...)
funcionará, mientras que SELECT com.path.to.MyBean(...)
no funcionará. @Query("SELECT ...")
, o @Query(value = "SELECT ...")
, o @Query(value = "SELECT ...", nativeQuery = false)
funcionará, mientras que @Query(value = "SELECT ...", nativeQuery = true)
no funcionará. Esto se debe a que las consultas nativas se pasan sin modificaciones al proveedor de JPA y se ejecutan contra el RDBMS subyacente como tal. Como new
y com.path.to.MyBean
no son palabras clave SQL válidas, el RDBMS arroja una excepción. Como se señaló anteriormente, la new ...
syntax es un mecanismo compatible con JPA y funciona con todos los proveedores de JPA. Sin embargo, si la consulta en sí no es una consulta JPA, es decir, es una consulta nativa, la new ...
syntax no funcionará ya que la consulta se pasa directamente al RDBMS subyacente, que no comprende la new
palabra clave desde no es parte del estándar SQL.
En situaciones como estas, las clases de bean deben reemplazarse con las interfaces de Spring Data Projection .
Paso 1 : Declarar una interfaz de proyección
package com.path.to; public interface SurveyAnswerStatistics { String getAnswer(); int getCnt(); }
Paso 2 : devolver las propiedades proyectadas de la consulta
public interface SurveyRepository extends CrudRepository { @Query(nativeQuery = true, value = "SELECT " + " v.answer AS answer, COUNT(v) AS cnt " + "FROM " + " Survey v " + "GROUP BY " + " v.answer") List findSurveyCount(); }
Use la palabra clave SQL AS
para asignar los campos de resultados a las propiedades de proyección para una asignación inequívoca.
Esta consulta de SQL devuelve List
Puedes hacerlo de esta manera:
@RestController @RequestMapping("/survey") public class SurveyController { @Autowired private SurveyRepository surveyRepository; @RequestMapping(value = "/find", method = RequestMethod.GET) public Map findSurvey(){ List
Sé que esta es una pregunta antigua y ya ha sido respondida, pero aquí hay otro enfoque:
@Query("select new map(count(v) as cnt, v.answer) from Survey v group by v.answer") public List> findSurveyCount();
defina una clase de pojo personalizada que diga sureveyQueryAnalytics y almacene el valor devuelto de la consulta en su clase de pojo personalizada
@Query(value = "select new com.xxx.xxx.class.SureveyQueryAnalytics(s.answer, count(sv)) from Survey s group by s.answer") List calculateSurveyCount();
No me gustan los nombres de tipos de Java en las cadenas de consulta y lo manejo con un constructor específico. Spring JPA llama implícitamente al constructor con el resultado de la consulta en el parámetro 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 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 findSurveyCount();