Update multiple records in an Oracle table in JPQL - oracle

Is it possible to update several rows in one JPQL query, using CASE...WHEN...THEN expression and parameters ? It is a table of an Oracle database.
Integer param1 = .....;
Integer param2 = .....;
Integer param3 = .....;
Query query = session.createQuery("update NumberEntity i set i.value = case "
+ "when (i.id=1) then ?1"
+ "when (i.id=2) then ?2"
+ "when (i.id=3) then ?3 else 0 end");
query.setParameter(1, param1);
query.setParameter(2, param2);
query.setParameter(3, param3);
#Entity
#Table(name = "Number")
public class NumberEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idNumber", nullable = false)
private Integer id;
#Basic(optional = false)
#Column(name = "value")
private Integer value;
.......
}
I obtained this error :
java.sql.SQLSyntaxErrorException: ORA-00932: inconsistent datatypes: expected CHAR got NUMBER
The resulting SQL query is : (I have previously simplified the query, as there are 9 id to distinguish)
UPDATE Nombre SET value = CASE WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? WHEN (idNumber = ?) THEN ? ELSE ? END
bind => [1, null, 2, null, 3, 0, 4, 363, 5, null, 6, null, 7, 0, 8, 57314, 9, 9, 0]
I have no char column. But the "value" column is of decimal type, whereas it is an Integer in my Entity. I though I will correct this later. I don’t understand why the error deals with CHAR.
session is an object using javax.persistence package.

Related

Getting Error Wrong number or types of arguments while calling stored procedure in Oracle using Spring Data Jpa

I have Oracle PL/SQL procedure as below
CREATE OR REPLACE FUNCTION getCollectorP2PSummary(inCollectorId IN VARCHAR2)
RETURN SYS_REFCURSOR
AS
p_cursor SYS_REFCURSOR;
BEGIN
OPEN p_cursor FOR
SELECT inCollectorId AS collectorId,
COALESCE(SUM(CASE WHEN A.PYMT_SCHD_SUM_STATUS_IND = 'BROKEN' AND TRUNC(TO_DATE(PYMT_SCHD_SUM_STATUS_DT, 'YYYYMMDD')) BETWEEN TRUNC(SYSDATE - INTERVAL '30' DAY) AND TRUNC(SYSDATE) THEN 1 ELSE 0 END), 0) as brokenInLast30Days,
COALESCE(SUM(CASE WHEN A.PYMT_SCHD_SUM_STATUS_IND = 'ACTIVE' THEN 1 ELSE 0 END), 0) AS activePromiseToPays,
COALESCE(SUM(CASE WHEN A.PYMT_SCHD_SUM_STATUS_IND = 'ACTIVE' THEN B.DLNQ_AMT ELSE 0 END), 0) as delinquencyAmount,
COALESCE(SUM(CASE WHEN A.PYMT_SCHD_SUM_STATUS_IND = 'ACTIVE' THEN A.TOTAL_SCHD_PYMT_AMT ELSE 0 END), 0) as promiseToPayAmount,
COALESCE(SUM(CASE WHEN A.PYMT_SCHD_SUM_STATUS_IND = 'ACTIVE' THEN A.TOTAL_SCHD_PYMT_AMT - A.total_actual_pymt_amt ELSE 0 END), 0) as remainingAmount,
COALESCE(COUNT(CASE WHEN A.PYMT_SCHD_SUM_STATUS_IND = 'ACTIVE' AND C.pymt_schd_status_ind = 'PENDING' THEN C.pymt_schd_sum_seq END), 0) as pendingPayments
FROM PYMT_SCHD_SUM A
LEFT JOIN COLL_ACCT B ON A.ACCT_NBR = B.ACCT_NBR
LEFT JOIN PYMT_SCHD C ON B.ACCT_NBR = C.ACCT_NBR
WHERE B.CLLCTR_ID = inCollectorId;
RETURN p_cursor;
END;
I'm calling it with JPA as below
ManagerSummaryEntity.java
#NamedStoredProcedureQuery(
name = "getManagerP2PSummary",
procedureName = "getManagerP2PSummary",
resultClasses = ManagerSummaryEntity.class,
parameters = {
#StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class),
#StoredProcedureParameter(mode = ParameterMode.IN, type = String.class)
}
)
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class ManagerSummaryEntity implements Serializable {
#Id
private String collectorId;
Long brokenInLast30Days;
Long activePromiseToPays;
BigDecimal delinquencyAmount;
BigDecimal promiseToPayAmount;
BigDecimal remainingAmount;
Long pendingPayments;
}
EntityManagerUtils.java
#Transactional
public Optional<ManagerSummaryEntity> getManagerP2PSummary(EntityManager entityManager, String collectorId) {
try {
StoredProcedureQuery query = entityManager.createNamedStoredProcedureQuery("getManagerP2PSummary");
query.setParameter(2, collectorId);
List<ManagerSummaryEntity> entities = (List<ManagerSummaryEntity>) query.getResultList();
if (query.execute()) {
return Optional.of(entities.get(0));
}
return Optional.empty();
} catch (RuntimeException e) {
log.error(e.getMessage());
return null;
}
}
However, I'm getting below error:
2023-02-07 10:09:16,284 ERROR [org.hib.eng.jdb.spi.SqlExceptionHelper] (executor-thread-0) ORA-06550: line 1, column 7: PLS-00306: wrong number or types of arguments in call to 'GETCOLLECTORP2PSUMMARY' ORA-06550: line 1, column 7: PL/SQL: Statement ignored
Can anyone tell me how to resolve this ?
P.S: I tried passing named parameter as well, but it didn't work either.

Hibernate, select where foreign key is null

I have entity as follows:
#Entity
#Table(name = "LORRY")
#NamedQueries({
#NamedQuery(name = "Lorry.findSuitableLorries",
query = "SELECT l from Lorry l " +
"WHERE l.order IS NULL")
})
public class Lorry {
#Id
#Column(name = "ID", length = 7)
#Pattern(regexp="[a-zA-Z]{2}\\d{5}")
#Size(min = 7, max = 7)
private String regNum;
#OneToOne(mappedBy = "lorry")
private Order order;
}
Now I need to select all rows where order id is null in the LORRY table, but it doesn't seem to work as I get empty list every time. How can I check if foreign key is null using JPQL?
Try either SELECT l from Lorry l WHERE l.order.id IS NULL or SELECT l from Lorry l left join l.order o WHERE o IS NULL

JPA query to work with daterange of postgresql

Actual DB table:
Column | Type | Collation | Nullable | Default
--------+-----------+-----------+----------+---------
room | text | | |
during | daterange | | |
Working DB query:
select * from room_reservation where during && daterange('[2020-10-15,2020-11-14)');
Entity Mapping:
#Column(name = "during", columnDefinition = "daterange")
private Range<Date> during;
Jpa Repository:
#Query(value = "select r.room from Room_Occupancy r where r.during && daterange('[?1, ?2)')", nativeQuery = true)
List<Long> findOccupiedRooms(#Param("d1") Date d1, #Param("d2") Date d2);
Exception:
Caused by: org.postgresql.util.PSQLException: ERROR: invalid input syntax for type date: "?1"
Position: 65
How can I write same query in JPA?
Here, '[?1, ?2)' inside string literal parameter can't be replaced. You can use || to concat as string where the parameters can be replaced.
#Query(value = "select r.room from Room_Occupancy r where r.during &&"
+ " daterange('[' || :d1 || ',' || :d2 || ')')", nativeQuery = true)
List<Long> findOccupiedRooms(#Param("d1") Date d1, #Param("d2") Date d2);
As it's a native query use ? as parameter placeholders:
#Query(value = "select r.room from Room_Occupancy r where r.during && daterange('[?, ?)')", nativeQuery = true)
List<Long> findOccupiedRooms(#Param("d1") Date d1, #Param("d2") Date d2);
Try this code:-
#Query(value = "select r.room from Room_Occupancy r where r.during >= ?1 and r.during < ?2", nativeQuery = true)
List<String> findOccupiedRooms(Date d1,Date d2); //d1 < d2
#Query(value = "select r.room from Room_Occupancy r where r.during && daterange(''||'[' || :d1 ||',' || :d2 ||')' || '')", nativeQuery = true)
List<Long> findOccupiedRooms(#Param("d1") Date d1, #Param("d2") Date d2);
This worked

Spring Data JPA QueryLimit

#Query(value = "SELECT e FROM user Order By e.id DESC LIMIT 0, :n ")
List findTopN(#Param("n") long n);
#Query(value = "SELECT * FROM event_tracker.user Order By user.id DESC LIMIT 0, :n",nativeQuery = true)
List findTopN(#Param("n") long n);

Pass date parameter to native query

A user can perform actions based on an occurrence value. When this value is equal to 'DAILY', I would like to retrieve all daily actions that have not been completed the last 24 hours.
The working SQL query:
SELECT distinct a.* FROM action as a LEFT OUTER JOIN history as h
ON a.id = h.action_id
AND h.user_id= <user> WHERE a.occurrence = 'DAILY' AND (h.id is NULL OR h.entry_date < TIMESTAMP 'yesterday')
The equivalent native query:
#Query(value =
"SELECT distinct a.* FROM action a "
+ "LEFT OUTER JOIN history h "
+ "ON a.id = h.action_id "
+ "AND h.user_id = :userId "
+ "WHERE a.occurrence='DAILY' AND (h.id IS NULL OR h.entry_date < :yesterday) ", nativeQuery = true)
public List<Action> findAllAvailableActions(#Param("userId") Long userId, #Param("yesterday") ZonedDateTime yesterday);
How it is called in my service :
ZonedDateTime today = ZonedDateTime.now(ZoneOffset.UTC);
ZonedDateTime yesterday = today.minus(1,ChronoUnit.DAYS);
Long userId = userDTO.getId();
List<Action> result = actionRepositoryCustom.findAllAvailableActions(userId, yesterday);
However, I do get the wrong results in my tests (actions that have already been completed are returned). I am afraid this is linked to the date parameter. The attribute entry_date is declared as ZoneDateTime in my entity. What am I doing wrong ?
hibernate : 5.2.4
You can't pass a ZonedDateTime into a native SQL query. You need to convert it to Calendar:
#Query(value =
"SELECT distinct a.* FROM action a "
+ "LEFT OUTER JOIN history h "
+ "ON a.id = h.action_id "
+ "AND h.user_id = :userId "
+ "WHERE a.occurrence='DAILY' AND (h.id IS NULL OR h.entry_date < :yesterday)", nativeQuery = true)
public List<Action> findAllAvailableActions(#Param("userId") Long userId, #Param("yesterday") Calendar yesterday);
And you can convert your ZonedDateTime this way:
public Calendar convertToDatabaseColumn(ZonedDateTime entityAttribute) {
if (entityAttribute == null) {
return null;
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(entityAttribute.toInstant().toEpochMilli());
calendar.setTimeZone(TimeZone.getTimeZone(entityAttribute.getZone()));
return calendar;
}
This approach is described here: link

Resources