Converting MySQL query into JPA to get count - java

Here I'm having a SQL query which is working fine to get count from the MySQL database which is as
#Query("SELECT count(is_accepted) as value, post_type, is_accepted from agent_activities where "
+ "YEAR(created_date_time) as year and post_type = 'ticket' " + "GROUP BY is_accepted")
And when I'm trying into Java as JPA query it's not working.
public interface AgentActivitiesRepo extends JpaRepository<AgentActivitiesEntity, Long> {
#Query("select new ProductIssuesModel"
+ "(count(data.isAccepted) as acceptCount) "
+ "from data where YEAR(data.createdDate) as :year "
+ "and data.postType = :postType " + "group by data.isAccepted")
public List<ProductIssuesModel> findAgentActivitiesYearly(Long year, String postType);
}
Here ProductIssuesModel is like:
public class ProductIssuesModel {
private Long acceptCount;
private Long rejectCount;
private Long year;
private Long month;
...}
By running above query, I face an error as:
Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: as near line 1, column 137 [select new com.accenture.icoe.fm.model.ProductIssuesModel(count(data.isAccepted) as acceptCount) from data where YEAR(data.createdDate) as :year and data.postType = :postType group by data.isAccepted]
Please let me know if you see any error.

There are two ways to write a JPQL -
Indexed Query Parameters
#Query("select new ProductIssuesModel"
+ "(count(data.isAccepted) as acceptCount) "
+ "from data where YEAR(data.createdDate) = ?1 "
+ "and data.postType = ?2 " + "group by data.isAccepted")
public List<ProductIssuesModel> findAgentActivitiesYearly(Long year, String postType);
The values of the parameters will be bind to the query based on the position/index.
Named Parameters
#Query("select new ProductIssuesModel"
+ "(count(data.isAccepted) as acceptCount) "
+ "from data where YEAR(data.createdDate) = :year "
+ "and data.postType = :postType " + "group by data.isAccepted")
public List<ProductIssuesModel> findAgentActivitiesYearly(#Param("year") Long year, #Param("postType") String postType);
In your case, the second approach is applicable.

Here , YEAR(data.createdDate) as :year is not a condtional expression.
You may be try to do this YEAR(data.createdDate) = :year.
And use #Param to use parameter in JPQL
#Query("select new ProductIssuesModel"
+ "(count(data.isAccepted) as acceptCount) "
+ "from data where YEAR(data.createdDate) = :year "
+ "and data.postType = :postType " + "group by data.isAccepted")
public List<ProductIssuesModel> findAgentActivitiesYearly(#Param("year") Long year, #Param("postType") String postType);

Related

Bind #param in a Jpa repository native query inside single quotations

I am looking for a way to bind a given param in a native query where the value has to be inside single quotations, like so:
#Transactional(readOnly = true)
#Query(value = " SELECT c.ID " +
" FROM table1 clh " +
" LEFT JOIN table2 nks " +
" on clh.SERIAL = nks.SERIAL_REF " +
" WHERE clh.CREATED_DATE >= :now - interval ':timeThreshold' HOUR " +
" AND nks.SERIAL_REF IS NULL" , nativeQuery = true)
List<Long> getIdsWithoutAnswer (#Param("timeThreshold") Integer timeThreshold, #Param("now") LocalDateTime now);
However, when I try to run this, it results in hibernate not being able to bind the timeThreshold value as it is provided inside the single quotations ''.
Does anyone know how this can be resolved?
The problem you are having with your native Oracle query has to do with trying to bind a value to an interval literal. You can't do that. Instead, use the NUMTODSINTERVAL() function:
#Transactional(readOnly = true)
#Query(value = " SELECT c.ID " +
" FROM table1 clh " +
" LEFT JOIN table2 nks " +
" on clh.SERIAL = nks.SERIAL_REF " +
" WHERE clh.CREATED_DATE >= :now - numtodsinterval(:timeThreshold, 'hour') " +
" AND nks.SERIAL_REF IS NULL" , nativeQuery = true)
List<Long> getIdsWithoutAnswer (#Param("timeThreshold") Integer timeThreshold, #Param("now") LocalDateTime now);

Spring boot jpa query can't update field

I have an update query on hibernate on this table
class PackEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String status;
private String oldStatus;
#ManyToOne
#JoinColumn(name = "order_id")
private OrderEntity order;
...
}
And on OrderEntity I have there another relationship to another table when I have machine names.
On the JPA repository, I have the query. Basically first I search by machine and status and then I want to update the old status to put the current value of the status field and in status to put the new status. This is it:
#Transactional
#Modifying(clearAutomatically = true)
#Query("UPDATE PackEntity p " +
"SET p.oldStatus= p.status, p.status = ?3 " +
"WHERE p.id IN " +
" ( SELECT p2" +
" FROM PackEntity p2" +
" JOIN p2.order " +
" JOIN p2.order.machine" +
" WHERE p2.order.machine.name = ?1 AND p2.status = ?2)")
List<PackEntity > updateAllWithStatusByMachineNameAndStatus(String machineName, String status, String newStatus);
Now I'm having this error .QueryExecutionRequestException: Not supported for DML operations [UPDATE com.pxprox.entities.PackEntity with root cause ...
Why not create a method that does this for you? Initializing the entity and updating everything, changes will be flushed automatically at the end of the transaction. You can have a look at updating entity with spring-data-jpa
It should basically be something like:
#Autowired
private PackEntityRepository packEntityRepository;
public void updatePackEntity(PackEntity newPE) {
PackEntity packEntity = packEntityRepository.findById(newPE.getId());
packEntity.setOldStatus = packEntity.getStatus();
packEntity.setStatus = newPE.getStatus();
packEntityRepository.save(packEntity);
}
The return type of the method is wrong and also the query should be a little adapted. Use the following:
#Transactional
#Modifying(clearAutomatically = true)
#Query("UPDATE PackEntity p " +
"SET p.oldStatus = p.status, p.status = ?3 " +
"WHERE EXISTS " +
" ( SELECT 1" +
" FROM PackEntity p2" +
" JOIN p2.order o " +
" JOIN o.machine m" +
" WHERE m.name = ?1 AND p2.status = ?2 AND p2.id = p.id)")
void updateAllWithStatusByMachineNameAndStatus(String machineName, String status, String newStatus);
or even better
#Transactional
#Modifying(clearAutomatically = true)
#Query("UPDATE PackEntity p " +
"SET p.oldStatus = p.status, p.status = ?3 " +
"WHERE p.status = ?2 AND EXISTS " +
" ( SELECT 1" +
" FROM p.order o " +
" JOIN o.machine m" +
" WHERE m.name = ?1)")
void updateAllWithStatusByMachineNameAndStatus(String machineName, String status, String newStatus);

How to translate from native sql to querydsl expression right?

Given the following native SQL query:
#Query(
value =
"SELECT "
+ "jp.BLABSTATUSID BlabStatus, "
+ "s.BLABSTATUSBEZ BlabStatusBez, "
+ "COUNT(*) sumvalue "
+ "FROM JP jp "
+ " LEFT JOIN BLAB_STATUS s "
+ " ON jp.BLABSTATUSID = s.BLABSTATUSID "
+ "GROUP BY jp.BLABSTATUSID, s.BLABSTATUSBEZ",
nativeQuery = true)
that I use in my Java / spring context, I have to switch to querydsl.
I tried:
final QJpEntity e = jpEntity;
final QBlabStatusEntity f = blabStatusEntity;
return jpaQueryFactory
.from(e)
.leftJoin(e.blabStatus, blabStatusEntity)
.on(blabStatusEntity.blabstatusid)
.groupBy(e.blabStatus.blabstatusid, f.blabstatusbez)
.select(
Projections.constructor(
JPStatisticCounter.class,
e.blabStatus,
f.blabstatusbez,
e.count()))
.fetch();
but it cannot compile because it seems syntactically wrong.
Any ideas?
solved, it was a constructor type mismatch

Implement JPA Projection with count

I want to implement JPA Projection with count. I tried this:
#Query(value = "SELECT new org.service.PaymentTransactionsDeclineReasonsDTO( id, count(id) as count, status, error_class, error_message) " +
" FROM payment_transactions " +
" WHERE terminal_id = :id AND (created_at > :created_at) " +
" AND (status != 'approved') " +
" GROUP BY error_message " +
" ORDER BY count DESC", nativeQuery = true)
List<PaymentTransactionsDeclineReasonsDTO> transaction_decline_reasons(#Param("id") Integer transaction_unique_id, #Param("created_at") LocalDateTime created_at);
But I get error: Caused by: java.sql.SQLException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.plugin.service.PaymentTransactionsDeclineReasonsDTO( id, count(id) as c' at line 1
How I can implement proper count when I have class based Projection?
Try Interface-based Projection instead of DTO:
public interface TransactionDeclineReason {
Integer getId();
Long getCount();
Status getStatus();
ErrorClass getErrorClass(); // I suppose it's enum...
String getErrorMessage();
}
#Query(value = "select " +
"id as id, " +
"count(id) as count, " +
"status as status, " +
"error_class as errorClass, " +
"error_message as errorMessage " +
"from " +
"payment_transactions " +
"where " +
"terminal_id = ?1 " +
"and created_at > ?2 " +
"and status != 'approved' " +
"group " +
"by error_message " +
"order by " +
"2 desc", nativeQuery = true)
List<TransactionDeclineReason> getTransactionDeclineReasons(Integer transactionId, LocalDateTime createdAt);
Pay attention on aliases (i.e. id as id) - they are mandatory.
You are mixing JPQL and SQL syntax.
The constructor expression (new ...) is JPQL, but in the annotation you mark it as a nativeQuery i.e. as SQL so you have to make up your mind.
If it is to be SQL I don't think you can use aliases in the ORDER BY clause, so you might have to either repeat the expression or wrap it in a subselect as described here: Using an Alias in a WHERE clause.
If it is to be JPQL it doesn't support aliases in a constructor expression, so I guess you have to repeat the expression in the order by clause.

Order By in #Query select not working

I have this Query in my JPA repository - and it works EXCEPT the " order by " part. Am i doing this wrong ? is it different in hql ?
#Query(value = "select wm.WagerIdentification, wm.BoardNumber, wm.MarkSequenceNumber, wm.MarkNumber," +
" pt.CouponTypeIdentification, pt.WagerBoardQuickPickMarksBoard " +
"from WagerBoard wb " +
"inner join wb.listOfWagerMarks wm " +
"inner join wb.poolgameTransaction pt " +
"where wb.WagerIdentification = wm.WagerIdentification and wb.BoardNumber = wm.BoardNumber and wb.GameIdentification = wm.GameIdentification and wm.meta_IsCurrent = 1 " +
"and wb.TransactionIdentification = pt.TransactionIdentification and pt.meta_IsCurrent = 1 " +
"and wb.meta_IsCurrent = 1 order by wm.WagerIdentification asc, wm.BoardNumber asc, wm.MarkNumber asc")
Instead of ordering result within the #Query, you can add a method parameter of type Sort, like in Spring Data JPA reference

Categories

Resources