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
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.
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
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
#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);
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