How to include the IN clause in the Query if the parameter is not null?
If I try to put the ":ramos is null" it gives an error
#Query(value = "SELECT r FROM ParceiroNegocio r " +
" WHERE (:razaoSocial is null or UPPER(r.razaoSocial) LIKE CONCAT('%',UPPER(:razaoSocial),'%')) " +
" AND (:nomeFantasia is null or UPPER(r.nomeFantasia) LIKE CONCAT('%',UPPER(:nomeFantasia),'%')) " +
" AND (:cnpj is null or r.cnpj =:cnpj) " +
" AND ((:ramos) is null or r.ramo IN (:ramos))")
Page<ParceiroNegocio> findByCnpjNomeFantasiaRazaoSocialRamoWithPagination(
#Param("razaoSocial") String razaoSocial,
#Param("nomeFantasia") String nomeFantasia,
#Param("cnpj") String cnpj,
#Param("ramos") List<Long> ramos,
Pageable pageable);
}
Error:
SqlExceptionHelperORA-00920: invalid relational operator
COALESCE helped me! :)
AND (COALESCE(:ramos) is null or r.ramo IN (:ramos))
Related
I have the following JpaRepository method:
#Query(value = "select * from default_price_view where product_code #> '{:productCode}'", nativeQuery = true)
Page<DefaultPriceView> findDefaultPricesByProductCode(Pageable pageable,
#Param("productCode") String productCode);
product_code is an array of strings with the format in Postgresql:
{021715,X91778,W21722}
Can you please tell me how I could add the parameter productCode into the query because currently it doesn't work :-(
Thank you in advance for your help,
If I understand well you have product_code is an array in Java, and in Postgresql it's with this format {021715,X91778,W21722}
If this is the case, Try to define a string :
String productCodeString = "{" + productCode[0] + "," + productCode[1]+ "," +productCode[2]+ "}";
and use it in your request :productCodeString
I am using Spring Data JPA (with Hibernate underneath, JPA 2.1) with TimescaleDB extension on PostgreSQL 13, and wish to use the time_bucket function. This takes the bucket_width which is an INTERVAL and time which is the TIMESTAMP column of the data.
I want to put this in a Spring Data Repository and want to use a JPQL #Query to extract the data into a projection that represents the aggregate counts, averages etc. for the returned time buckets. I don't want to use a native query, because I want to join with some other tables, and populate their entities automatically.
I registered the time_bucket function to the PostgisPG95Dialect I am extending, like this:
public class CustomPostgresqlDialect extends PostgisPG95Dialect {
public CustomPostgresqlDialect() {
super();
this.registerFunction("time_bucket", new StandardSQLFunction("time_bucket", new OffsetDateTimeType()));
}
}
If the bucket_width is hardcoded, all this works fine. But I want the bucket_width to be a parameter of the query method.
The following works fine:
#Query("select sys as system, "
+ "function('time_bucket', '10 mins', vt.ts) as startTime, "
+ "count(vt) as total, avg(vt.speed) as avgSpeed "
+ "from Data vt "
+ "JOIN vt.system sys "
+ "where sys.sysId = :sysId and "
+ "function('time_bucket', '10 mins', vt.ts) between :from and :to "
+ "group by system, startTime "
+ "order by startTime")
List<SummaryAggregate> getSummaryData(
#Param("sysId") String sysId,
#Param("from") OffsetDateTime from,
#Param("to") OffsetDateTime to);
But when I try to parameterise the interval I can't get it to work. I tried passing the interval as a string, since that is how it is being written in the hardcoded version:
#Query("select sys as system, "
+ "function('time_bucket', :grouping, vt.ts) as startTime, "
+ "count(vt) as total, avg(vt.speed) as avgSpeed "
+ "from Data vt "
+ "JOIN vt.system sys "
+ "where sys.sysId = :sysId and "
+ "function('time_bucket', :grouping, vt.ts) between :from and :to "
+ "group by system, startTime "
+ "order by startTime")
List<SummaryAggregate> getSummaryData(
#Param("sysId") String sysId,
#Param("from") OffsetDateTime from,
#Param("to") OffsetDateTime to,
#Param("grouping") String grouping);
where grouping is passed a value like 10 mins.
But for this I get this error:
SQL Error: 0, SQLState: 42883
ERROR: function time_bucket(character varying, timestamp with time zone) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 61
I then tried to change it to a Duration, since Hibernate translates Duration to PostgreSQL Interval types
#Query("select sys as system, "
+ "function('time_bucket', :grouping, vt.ts) as startTime, "
+ "count(vt) as total, avg(vt.speed) as avgSpeed "
+ "from Data vt "
+ "JOIN vt.system sys "
+ "where sys.sysId = :sysId and "
+ "function('time_bucket', :grouping, vt.ts) between :from and :to "
+ "group by system, startTime "
+ "order by startTime")
List<SummaryAggregate> getSummaryData(
#Param("sysId") String sysId,
#Param("from") OffsetDateTime from,
#Param("to") OffsetDateTime to,
#Param("grouping") Duration grouping);
But I still got the same error, this time it is thinking that the Duration is a bigint not an Interval.
SQL Error: 0, SQLState: 42883
ERROR: function time_bucket(bigint, timestamp with time zone) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 61
Is there a way to parameterise an Interval using JPQL?
There is a way, but you will have to register a custom function for this purpose because you can't cast to an arbitrary SQL type.
public class CastInterval implements SQLFunction {
#Override
public boolean hasArguments() {
return true;
}
#Override
public boolean hasParenthesesIfNoArguments() {
return true;
}
#Override
public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException {
return firstArgumentType;
}
#Override
public String render(Type firstArgumentType, List args, SessionFactoryImplementor factory) throws QueryException {
return "cast(" + args.get(0) + " as interval)";
}
}
You will have to register the function within the Dialect.
So if the Dialect is being extended as indicated, this would be done with something like:
this.registerFunction("castInterval", new CastInterval());
Then you can use it like this: function('time_bucket', castInterval(:grouping), vt.ts)
Am trying to execute a Named Query using JPA. Query has to search and pull the records based on criteria of the query. Criteria is query should pull the records between specific given times(Records between From and To Dates provided) and name of the Application.
Query works fine, when executed in Postgresql. But, through JPA it gives error while executing the query
Here is my Query in PostgreSQL :
SELECT auditLog.busn_sys_id
, sourceSystem.busn_sys_full_nm
, auditLog.purge_ts
, auditLog.rec_purge_cnt
FROM rec_ret.rec_rtn_purge_adt auditLog
LEFT JOIN gbl_dm.gbl_busn_sys_dm sourceSystem on (auditLog.busn_sys_id = sourceSystem.busn_sys_id)
WHERE (auditLog.purge_ts BETWEEN '2019-08-19' AND '2019-08-25')
and sourceSystem.busn_sys_full_nm like 'PROFILE'
order by auditLog.busn_sys_id ;
Here is my JPA implementation to get Results List
try{
Query query = entityManager.createNativeQuery("SELECT auditLog.busn_sys_id, sourceSystem.busn_sys_full_nm, auditLog.purge_ts, auditLog.rec_purge_cnt " +
"FROM rec_ret.rec_rtn_purge_adt auditLog " +
"LEFT JOIN gbl_dm.gbl_busn_sys_dm sourceSystem on (auditLog.busn_sys_id = sourceSystem.busn_sys_id) " +
"WHERE (auditLog.purge_ts BETWEEN auditLog.purge_ts = :requestedFrom AND auditLog.purge_ts = :requestedTo) " +
//"WHERE (auditLog.purge_ts BETWEEN requestedFrom = (?) AND requestedTo = (?)) " +
"and sourceSystem.busn_sys_full_nm = :sourceSystem " +
"order by auditLog.busn_sys_id ");
query.setParameter("requestedFrom",auditLogCriteria.getFromDate());
query.setParameter("requestedTo",auditLogCriteria.getToDate());
query.setParameter("sourceSystem",auditLogCriteria.getSourceSystem());;
query.executeUpdate();
return query.getResultList();
}catch (Exception e){
logger.error("Fetching of logs failed with message : " + e.getMessage());
throw e;
}
Here is my implementation of Entity/Model class code
#NotNull (message = "Name of the Source System should be entered")
private String sourceSystem;
#NotNull (message = "Specify FromDate to filter records")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss[.SSS]")
#Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime fromDate;
#NotNull (message = "Specify ToDate to filter records")
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss[.SSS]")
#Convert(converter = LocalDateTimeConverter.class)
private LocalDateTime toDate;
\\ Getters and Setters
Here is the Error :
Hibernate: SELECT auditLog.busn_sys_id, sourceSystem.busn_sys_full_nm, auditLog.purge_ts, auditLog.rec_purge_cnt FROM rec_ret.rec_rtn_purge_adt auditLog LEFT JOIN gbl_dm.gbl_busn_sys_dm sourceSystem on (auditLog.busn_sys_id = sourceSystem.busn_sys_id) WHERE (auditLog.purge_ts BETWEEN auditLog.purge_ts = ? AND auditLog.purge_ts = ?) and sourceSystem.busn_sys_full_nm = ? order by auditLog.busn_sys_id
[ERROR] 2019-08-29 10:02:00.558 [http-nio-8080-exec-2] SqlExceptionHelper - ERROR: operator does not exist: timestamp without time zone >= boolean
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 267
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not execute statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1593)
So, result should be all the records matching with the criteria has to be returned as a response to JSON request
This part of your JPA query looks wrong:
BETWEEN auditLog.purge_ts = :requestedFrom AND auditLog.purge_ts = :requestedTo
I think it should be:
BETWEEN :requestedFrom AND :requestedTo
I am using JDBI 3 to run update query which might update multiple rows. I want to get updated rows from the resultset.
However, I'm getting ArrayIndexOutOfBoundsException: Error thrown mapping result set into return type
Tried to add #SingleValue to return signature, but still stuck with the same issue.
Unable to use #SqlBatch as this is a single query and #SqlBatch requires list.
#SqlUpdate(
"UPDATE task_sync SET "
+ " is_active = false, "
+ " version = version+1 "
+ " WHERE task_id IN (<taskIdList>) "
+ " AND barcode IN (<barcodeList>) "
+ " AND is_active = true ")
#GetGeneratedKeys("id")
List<Long> deactivateTaskSyncByTaskIdInAndBarcodeList(
#BindList("taskIdList") List<Long> taskIdList,
#BindList("barcodeList") Set<String> barcodeList,
#Bind("lastUpdatedById") Long lastUpdatedById);
Query generated:
UPDATE task_sync SET is_active = false, version = version+1 WHERE task_id IN (26) AND barcode IN ('8606850380_0', '8696930120_0', '6907922280_0', '4605723180_0', '2354050010_0', '5259987660_0', '6392185330_0'
) AND is_active = true
RETURNING "id"
I expect this to return a list of updated ids.
You are in the right track.
To make it work you need to tell Postgres that you want to return the id column of all affected rows. You can do this by a adding RETURNING id; to the end of your query. The code would look like this:
#SqlUpdate(
"UPDATE task_sync SET "
+ " is_active = false, "
+ " version = version+1 "
+ " WHERE task_id IN (<taskIdList>) "
+ " AND barcode IN (<barcodeList>) "
+ " AND is_active = true RETURNING id;")
#GetGeneratedKeys("id")
List<Long> deactivateTaskSyncByTaskIdInAndBarcodeList(
#BindList("taskIdList") List<Long> taskIdList,
#BindList("barcodeList") Set<String> barcodeList,
#Bind("lastUpdatedById") Long lastUpdatedById);
Notice that you can also return multiple columns (e.g.: RETURNING id, version;) or event the entire row (e.g: RETURNING *;).
I have a Spring-Boot app that has some native queries that use content projection. It runs Postgres in production and works fine. I'm trying to set up integration tests for the repositories using #DataJpaTest and a h2 in-memory database, but my queries that are using content projection are failing with a JdbcSQLException out of the driver:
org.h2.jdbc.JdbcSQLException: Column count does not match
I successfully save to the TestEntityManager, so there are records in the database, but I am unable to invoke the SELECT via the repository method. It works properly in production on Postgres -- is this a limitation to h2 and is there a workaround I could apply so I can properly test this?
The repository method looks like this (one inner join, two params in the where clause, table names and columns changed to protect the guilty):
public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {
#Query(nativeQuery = true,
value = "SELECT order.id, order.total, pizza.name " +
"FROM example.order " +
"INNER JOIN example.pizza USING (pizza_id) " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate ",
countQuery = "SELECT count(order.id) " +
"FROM example.order " +
"INNER JOIN example.pizza USING (pizza_id) " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate")
<T> Page<T> findAllByCustIdAndOrderDate(String custId, OffsetDateTime orderDate, Pageable paging, Class<T> type);
}
And the projection looks like this:
public interface PizzaOrderProjection {
Long getId();
Double getTotal();
String getName();
}
The exception triggers when I call findAllByCustIdAndOrderDate, and the SQL statement that it prints is causing it is the SELECT. The SELECT it prints looks perfectly normal:
Hibernate:
/* dynamic native SQL query */ SELECT
order.id,
order.total,
pizza.name
FROM
example.order
INNER JOIN
example.pizza USING (pizza_id)
WHERE
order.customer_id = ?
AND order.order_date = ? limit ?
2019-04-09 12:42:18.704 WARN 17568 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 21002, SQLState: 21S02
2019-04-09 12:42:18.708 ERROR 17568 --- [ main] o.h.engine.jdbc.spi.SqlExceptionHelper : Column count does not match; SQL statement:
It turns out that the error message actually has nothing to do with the underlying issue.
The H2 database does not support the using keyword on the inner join clause, only the on keyword.
The issue was resolved by changing the inner join to use on instead, like this:
public interface OrderRepository extends PagingAndSortingRepository<Order, Long> {
#Query(nativeQuery = true,
value = "SELECT order.id, order.total, pizza.name " +
"FROM example.order " +
"INNER JOIN example.pizza ON order.pizza_id = pizza.pizza_id " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate ",
countQuery = "SELECT count(order.id) " +
"FROM example.order " +
"INNER JOIN example.pizza ON order.pizza_id = pizza.pizza_id " +
"WHERE order.customer_id = :custId " +
"AND order.order_date = :orderDate")
<T> Page<T> findAllByCustIdAndOrderDate(String custId, OffsetDateTime orderDate, Pageable paging, Class<T> type);
}
This change makes the queries valid in both postgres and h2.