i am trying to update rows with optional parameters, but i am getting error with below query.
#Modifying
#Transactional
#Query("UPDATE Visit visits SET "
+ " visits.approvalStatus is null OR visits.approvalStatus = :approvalStatus "
+ " , visits.declineReason is null OR visits.declineReason =:declineReason "
+ " WHERE visits.visitId in :visitIds ")
public int patchUpdate(#Param("approvalStatus") String approvalStatus,
#Param("declineReason") String declineReason, #Param("visitIds") List<Integer> visitIds);
error logs :
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: expecting EQ, found 'is' near line 1, column 69 [UPDATE com.quest.vms.entity.Visit visits SET visits.approvalStatus is null OR visits.approvalStatus = :approvalStatus WHERE visits.visitId in :visitIds ]
Edited to add info : here i want to update a particular field when new data is not null, otherwise that parameter should be ignored.
Thanks for your help
is null is used for checking the field.
For setting column on the basis of condition you can use:
UPDATE Visit visits SET "
+ " visits.approvalStatus = CASE "
+ " WHEN visits.visitId in :visitIds THEN :approvalStatus "
+ " ELSE NULL "
+ " END"
There is a syntax error in the UPDATE query, the part to set a field value is missing.
Possibly a query using COALESCE function (or a native query using functions such as IsNull, NullIf, NVL) could be helpful:
#Query("UPDATE Visit visits SET "
+ "visits.approvalStatus = COALESCE(:approvalStatus, approvalStatus) "
+ "visits.declineReason = COALESCE(:declineReason, declineReason) "
+ " WHERE visits.visitId in :visitIds")
public int patchUpdate(
#Param("approvalStatus") String approvalStatus,
#Param("declineReason") String declineReason,
#Param("visitIds") List<Integer> visitIds
);
Or using similar CASE statement
#Query("UPDATE Visit visits SET "
+ "visits.approvalStatus = (CASE :approvalStatus WHEN NULL THEN approvalStatus ELSE :approvalStatus END) "
+ "visits.declineReason = (CASE :declineReason WHEN NULL THEN declineReason ELSE :declineReason END) "
+ " WHERE visits.visitId in :visitIds")
public int patchUpdate(
#Param("approvalStatus") String approvalStatus,
#Param("declineReason") String declineReason,
#Param("visitIds") List<Integer> visitIds
);
You can add a case condition while setting data like
UPDATE
Visit visits
SET
visits.approvalStatus = (
case
when :approvalStatus is null
then visits.approvalStatus
else :approvalStatus
end
),
visits.declineReason = (
case
when :declineReason is null
then visits.declineReason
else :declineReason
end
),
WHERE visits.visitId in :visitIds
If passed value is null, you set the value you have in db, otherwhile set the passed value.
Related
I am using JPA-Hibernate in our application and I am working with a query like :
#Query(
value = "ReportDTO(report) FROM Report report " +
"JOIN p.clientFile cf " +
"JOIN cf.client cl " +
"WHERE report.active = TRUE " +
"AND :companyKey = CASE WHEN report.companyKey IS NOT NULL " +
"THEN report.companyKey " +
"ELSE cl.companyKey " +
"END " +
"ORDER BY report.publishedDate DESC",
countQuery = “..”
)
#NonNull
Page<TagReportDTO> findAll(#NonNull Pageable pageable, #Param("companyKey") String companyKey);
when the "companyKey" was a single value, it worked. Now, I need to change this findAll method to accept a list of company keys. So it should like like ( after the change) :
#NonNull
Page<TagReportDTO> findAll(#NonNull Pageable pageable, #Param("companyKeys") List<String> companyKeys);
Now I am getting hard time to accommodate the list of objects or companyKeys (instead of :companyKey) in the query where the the case statement will be applicable to each item in the list. Is there a way I can loop through ?
Did you try using IN operator? Like this:
"AND (CASE WHEN report.companyKey IS NOT NULL " +
"THEN report.companyKey " +
"ELSE cl.companyKey " +
"END) IN :companyKeys "
Update
I've changed the first method to return a List, but I get the same exception.
I have 2 native queries in my Repository class. One is typed to return all records, the other returns just one row. See below:
#Query(nativeQuery = true, value = NATIVE_SUMMARY_QUERY_PARTIAL + "group by (rjd.refresh_job_identifier)) as rc")
List<RefreshSummary> getRefreshJobDetailSummary();
#Query(nativeQuery = true, value = NATIVE_SUMMARY_QUERY_PARTIAL + " WHERE rjd.refresh_job_identifier = :refreshJobId" +
" group by (rjd.refresh_job_identifier)) as rc")
List<RefreshSummary> getRefreshJobDetailSummaryById(#Param("refreshJobId") String refreshJobId);
interface RefreshSummary {
String getRefreshJobId();
Date getRefreshJobStart();
Date getRefreshJobComplete();
String getUserId();
long getTotalRecords();
long getSuccessfulRecords();
long getPendingRecords();
long getErrorRecords();
long getCancelledRecords();
String getRefreshJobStatus();
}
String NATIVE_SUMMARY_QUERY_PARTIAL = "SELECT rc.refresh_job_identifier as refresh_job_id, ..."
The first method, getRefreshJobDetailSummary, works fine. But the second method, where I want only one row, gives me this exception:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [com.company.repository.RefreshJobDetailRepository$RefreshSummary]
The full query looks like this:
String NATIVE_SUMMARY_QUERY_PARTIAL = "SELECT rc.refresh_job_identifier as refresh_job_id, " +
"rc.refresh_job_start_time as refresh_job_start, " +
"rc.record_completion_time as refresh_job_complete, " +
"rc.user_id as user_id, " +
"rc.pending + rc.successful + rc.cancelled + rc.error as total_records, " +
"rc.successful as successful_records, " +
"rc.pending as pending_records, " +
"rc.error as error_records, " +
"rc.cancelled as cancelled_records, " +
"CASE WHEN pending > 0 THEN 'In progress' " +
"ELSE 'Complete' " +
"END as refresh_job_status " +
"FROM " +
"(SELECT rjd.refresh_job_identifier as refresh_job_identifier, " +
"MAX(rjd.refresh_job_start_time) as refresh_job_start_time, " +
"MAX(rjd.record_completion_time) as record_completion_time, " +
"MAX(rjd.org_usr_nu) as user_id, " +
"SUM(CASE WHEN LOWER(record_status) = 'pending' THEN 1 ELSE 0 END) as pending, " +
"SUM(CASE WHEN LOWER(record_status) = 'successful' THEN 1 ELSE 0 END) as successful, " +
"SUM(CASE WHEN LOWER(record_status) = 'cancelled' THEN 1 ELSE 0 END) as cancelled, " +
"SUM(CASE WHEN LOWER(record_status) = 'error' THEN 1 ELSE 0 END) as error " +
"from erd_cfg_owner.refresh_job_detail rjd " ;
And the value the query returns looks like this:
'{20191218204913458hc35, 2019-12-18 20:49:13.314, 2019-12-18 20:49:24.335, hc35, 1, 1, 0, 0, 0, Complete}'
Can someone shed any light on this? Why would one method work but not the other?
I would replace the return type of your 2nd method from RefreshSummary to List<RefreshSummary>. In theory your method is supposed to return a list not a single value
Could you try using constructor expression in query declaration or by creating custom converter.
Eg-SELECT NEW com.example.MyClass(e.attribute1, e.attribute2...) FROM MyEntity e");
Unable to pass named parameters in #NamedNativeQuery in spring data jpa
my repo:
#Query(value = "select stat.desc as desc," +
" stat.priority as priority," +
" (case when sum(activeUser) is null then 0 else sum(activeUser) end) as activeUser," +
" (case when sum(totalUser) is null then 0 else sum(totalUser) end) as totalUser" +
" from lookup.user stat left outer join" +
" (" +
" select user.role as role, " +
" sum (case when user.STATUS = 'ACTIVE' then 1 else 0 end) as activeUser," +
" count(*) as totalUser," +
" user.group as group" +
" from Ctrl.user user" +
" where user.group =:userGroup " +
" and user.branch_code =:branchCode " +
" group by user.role,user.group" +
" ) as tbl on stat.role = tbl.role and stat.group = tbl.group" +
" where stat.group =:userGroup " +
" group by stat.desc, stat.priority" +
"", nativeQuery = true)
public List<com.cimb.dto.UserStatusSummary> getSummaryReport(#Param(value = "userGroup") String userGroup, #Param(value = "branchCode") String branchCode);
The underlying database is DB2
When I tried to access that method I am hitting following error.
DB2 SQL Error: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.25.13
if I hard code those named parameters with values then it's working.
I can not use jpql as real queries have some subqueries in it, so I cant use JPQL
Edit Update
After some digging, I have found out that, the parameters I am passing are in the subquery, since JPA don't have subquery concept it's not injecting into named parameters which resulting in a syntax error.
Now how to work with Subqueries in JPA
Please help.
I wrote a SQL query which updates the record, in most cases it runs fine, but from yesterday it fails to update the row.I am currently working on Spring MVC based Web application, in which I need to perform the DML operation by calling update()method.
I am using JDBC template and in my update method i wrote this query.
It fetches the 947 records for January month 2018 and I already checked all records are unique.
I am here stuck, i am not able to find the duplication of record.I thought this exception occurred because of multiple record, but I think i am wrong, there is something which i am not able to identify.
Here is the query:
UPDATE SALARY_DETAIL_REPORT_012018 sd
SET sd.EMP_ID =
(SELECT e.emp_id from EMPLOYEE e
WHERE e.VERIFY_STATUS = 1
AND e.RELIEF_TYPE IS NULL
AND e.emp_code = to_char(sd.emp_code)
AND e.EMP_TYPE_ID!=03)
WHERE EXISTS
(SELECT e.emp_id from EMPLOYEE e
WHERE e.VERIFY_STATUS = 1
AND e.emp_code = to_char(sd.emp_code)
AND e.EMP_TYPE_ID!=03 AND e.RELIEF_TYPE IS NULL)
AND sd.EMP_ID IS NULL
AND sd.REFERENCE_ID LIKE '203-%'
and HERE is Java Code in my DAOImpl class
public void update(String tableSuffix, String regionId, String circleId) {
String tabName = "SALARY_DETAIL_REPORT_" + tableSuffix;
String q = "UPDATE " + tabName + " sd"
+ " SET sd.EMP_ID = (SELECT e.emp_id "
+ " from EMPLOYEE e WHERE e.VERIFY_STATUS = 1 AND e.RELIEF_TYPE IS NULL "
+ " AND e.emp_code = to_char(sd.emp_code) AND e.EMP_TYPE_ID!=03) "
+ " WHERE "
+ " EXISTS (SELECT e.emp_id from EMPLOYEE e WHERE e.VERIFY_STATUS = 1 "
+ " AND e.emp_code = to_char(sd.emp_code) AND e.EMP_TYPE_ID!=03 AND e.RELIEF_TYPE IS NULL) "
+ " AND sd.EMP_ID IS NULL";
if (circleId != null && !circleId.trim().equals("")) {
q += " AND sd.REFERENCE_ID LIKE '" + circleId + "-%' ";
} else {
q += " AND sd.REFERENCE_ID LIKE '" + regionId + "-%' ";
}
// System.out.println("q " + q);
MapSqlParameterSource param = new MapSqlParameterSource();
getNamedParameterJdbcTemplate().update(q, param);
}
Please suggest me the best solution
You need to find the rows that prevent your query from running.
Run this query:
SELECT sd.emp_code, COUNT(*) as cnt
FROM EMPLOYEE e
WHERE e.VERIFY_STATUS = 1 AND
e.RELIEF_TYPE IS NULL AND
e.emp_code = to_char(sd.emp_code) AND
e.EMP_TYPE_ID <> 03
GROUP BY sd.emp_code
HAVING COUNT(*) > 1;
This has the candidate problems. What can you do? The simplest thing is one of the problems:
Change the SELECT to SELECT MAX(sd.emp_code)
Change the WHERE with AND rownum = 1
#Query(value = "Select f from Documents f " +
"RIGHT JOIN f.documentStatus ds " +
"where f.billingAccount.accountId in :billingAccountIdList " +
" and ds.statusCode in :paymentStatuses" +
" and f.paymentDate < :paymentDate")
List<FinancialDocumentEntity> getFinancialDocumentsOverdue(#Param("billingAccountIdList")List<String> billingAccountIdList,
#Param("paymentStatuses") List<String> paymentStatuses,
#Param("paymentDate") Date paymentDate);
I have query like above. It is possible to skip searching param for example #Param("paymentStatuses") in query method if is null or is empty ?
Try changing
" and ds.statusCode in :paymentStatuses"
into
" and (:paymentStatuses is null or ds.statusCode in :paymentStatuses)"
Try changing
" and ds.statusCode in :paymentStatuses"
into
" and (COALESCE(:paymentStatuses, null) is null or ds.statusCode in :paymentStatuses)"
This solution will work for the empty list, null list, and a list with items 1 or more.