How to calculate average on a column with JPA? - spring-boot

I would like to calculate average on a column.
I tried the following:
#Query("SELECT AVG(e.rating) FROM user_rating e WHERE e.route_uid = ?1")
fun averageOfRateings(routeId: UUID): Long
The query works in Sql, however I get the following error when I run the code in Spring Boot.
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException:
user_rating is not mapped [SELECT AVG(e.rating) FROM user_rating e WHERE e.route_uid = ?1]
What would be the right syntax? What is the problem with the mapping of my table?

you must use the entity name, not the table.The same applies for the column name, you must use the field name instead.
I assume your entity is UserRating, so the correct query will be:
#Query("SELECT AVG(e.rating) FROM UserRating e WHERE e.routeUid = ?1")
Or second option specify that is native query:
#Query(value = "SELECT AVG(e.rating) FROM user_rating e WHERE e.route_uid = ?1" , nativeQuery = true)

Related

How to add optional parameter in JPQL?

How to use/add optional parameter in JPQL?
#Query(value = "SELECT stud FROM Student stud where stud.name = :studentName AND stud.age IN :studentAgeList")
List<Student> getStudents(
#Param("studentName ") String studentName,
#Param("studentAgeList") List<Integer> studentAgeList
)
How to make studentAgeList parameter in above query ?
I tried below :
#Query(value = "SELECT stud FROM Student stud where stud.name = :studentName AND (:studentAgeList IS NULL OR stud.age IN :studentAgeList))
List<Student> getStudents(
#Param("studentName ") String studentName,
#Param("studentAgeList") List<Integer> studentAgeList
)
But getting error : unexpected AST node:
Tried above but getting error
JPQL does not support optional parameters, you can use overload methods with different queries or criteria API or JPA specifications.
may be get answer here: Set optional parameters in JPQL Query

Spring JPA #Query throws Optional parameter exception with Specification and Param

I'm writing a larger query in JPA and need the pagination, specification and an additional parameter to work in it. I wanna function look like this.
#Query(value = QRY_DATA, countQuery = QRY_DATA_COUNT)
Page<NotificationUserSettingsPageResponse> findAllFrontend(#Nullable Specification<NotificationUserSettings>
spec, Pageable pageable, #Param("user_UUID") String userUUID);
when i try perform query like this i get error
but parameter 'Optional[spec]' not found in annotated query
when i delete last param from query and function it work fine but when i add param JPA try to use Specification like param.
I mention that i need this param to use in join so i can't move it to specification. Query below.
SELECT new pl.notification.dto.response.NotificationUserSettingsPageResponse(s.id,
s.userUUID, n.id,
n.system, n.name, n.category,
b.id, b.businessRule,
CASE WHEN s.id > 0
THEN s.isEmail ELSE 'T' END AS is_email,
CASE WHEN s.id > 0
THEN s.isSMS ELSE 'T' END AS is_sms,
CASE WHEN s.id > 0
THEN s.isPortal ELSE 'T' END AS is_portal)
FROM BusinessRuleConfig b
RIGHT JOIN NotificationConfig n on n.id = b.notificationConfig.id
LEFT JOIN NotificationUserSettings s on s.id = n.id AND s.id = b.id AND s.userUUID =:user_UUID
Seems, you are extend just the JpaRepository for your repository.
You may extend your repo:
#Repository
public interface NotificationUserSettingsPageResponseRepository extends JpaRepository<NotificationUserSettingsPageResponse, Long>, JpaSpecificationExecutor<NotificationUserSettingsPageResponse> {
#Query(value = QRY_DATA, countQuery = QRY_DATA_COUNT)
Page<NotificationUserSettingsPageResponse> findAllFrontend(#Param(value = "user_UUID") String userUUID, Pageable pageable);
}
P.S. And use Pageable argument the last.

JPA find first by created in given list

I have a model class which has these fields:
class Student {
Long roleNo;
Long version;
Date createdAt;
Date updateAt;
}
Now I'm trying to write a JPA query in which I can pass a list of role numbers and for every role number I can get a latest record by version.
I tried to do this but I'm only getting one record:
findFirstByRoleNoIn(List<Long> roleNo);
One way is to make use of #Query annotation to write simple query. Sample query for your case:
#Query(nativeQuery = true, value = """
SELECT s.* FROM student s
INNER JOIN (SELECT
role_no,
MAX(version) AS latest
FROM student GROUP BY role_no) t_version
ON s.role_no = t_version.role_no
AND s.version = t_version.latest
WHERE s.role_no IN (:roleNo)
""")
findLatestVersion(#Param("roleNo") List<Long> roleNo);

spring jpa query SQLGrammarException on join #ManyToMany

I have Way POJO in my Spring Boot application, here is what it looks like:
public class Way {
#Id
private Long wayID;
#ToString.Exclude
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY,cascade=CascadeType.ALL)
private List<Relation> relations=new ArrayList<>();
Now I want to select all the ways that has relationID of a given value.
relationID is a member of Relation POJO.
So here is my query
#Query("select w from Way w join Relation relations where relations.relationID=?1")
List<Way> selectAllWaysByRelationID(Long relationID);
But the error seems to be in my JOIN portion, it crashes and says:
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select way0_.wayid as wayid1_5_ from way way0_ inner join relation relation1_ on where relation1_.relationid=?]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
How can I resolve this ?
I also tried this:
#Query("select way from Way.relations full join Way.relations rel where rel.relationID=?1")
List<Way> selectAllWaysByRelationID(Long relationID);
This too:
#Query("select way from Way way join Way.relations rel where rel.relationID=?1")
List<Way> selectAllWaysByRelationID(Long relationID);
When using JOIN you need to use alias of Way with relations field like this, w.relations r instead of Way.relations.
The complete query is below:
#Query("select w from Way w join w.relations r where r.relationID=?1")
List<Way> selectAllWaysByRelationID(Long relationID);

Spring Data JPA Repository returns Object[] instead of MyType while using Sum Function

Until today I was using this statement:
#Query(value = "select top 5 p.*, sum(po.quantity) as total_quantity from product p " +
"inner join productorder po " +
"on p.id = po.product_id " +
"group by p.id, p.name " +
"order by total_quantity desc", nativeQuery = true)
List<Product> findTopFiveBestSellerNative();
Here as i define the return type as a list of Products, i exactly get what i need. And the selected column total_quantity is simply ignored.
Lastly i needed to integrate pagination into this query. Since Spring does not support pagination handling with native queries, i wanted to first transform this query to JPQL (then i will add pagination). And now it looks like this:
#Query(value = "select p, sum(po.quantity) as total_quantity " +
"from Product p, ProductOrder po " +
"where p.id = po.pk.product " +
"group by p.id, p.name " +
"order by total_quantity desc")
List<Product> findTopFiveBestSeller();
The return type is now a list of object arrays, where the first element of array is Product, and second one is the total_quantity. (Although the method signature says List..)
How can i change my statement or somehow achieve this, so that i do not have to deal with array, and simply just get my Product objects?
EDIT: I had the idea to use this query as a subquery, and just select the products from the subquery. It turns out that the JPQL cannot do subqueries in the 'from' clause..
Fact is your query is not returning only the columns needed to build a Product object, so Spring JPA is mapping it to an object.
Create an aggregate entity that extends product and that contains the property totalQuantity and map your query to it (possibly in another repository)

Resources