INTERVAL expression in Spring Data JPA Native Query - java

I have Spring JPA.
I have a query like this in sql oracle:
SELECT * FROM MY_TABLE WHERE SYSDATE > MY_DATE + INTERVAL '10' DAY;
I have a CrudRepository in which I use the above query in native mode, like this:
#Query(nativeQuery = true,
value = "SELECT * FROM MY_TABLE WHERE SYSDATE > MY_DATE + INTERVAL :myValue DAY")
public List<Object[]> myMethod(#Param("myValue") String myValue );
I get ORA-00933:
Passing myValue as integer between quotes I get ORA-01867
Passing myValue as integer without quotes I get ORA-00933
How to do it?

See comments on question, there is a similar question/answer for spring/jpa/postgresql, solution for me is:
#Query(nativeQuery = true,
value = "SELECT * FROM MY_TABLE WHERE SYSDATE > MY_DATE + :myValue * (INTERVAL 1 DAY"))
public List<Object[]> myMethod(#Param("myValue") int myValue );

Related

I got a syntax error when trying to call JPA function

When Im trying to call JPA function this statement I got an error: syntax error at or near ":"
public interface BcaTestRepository extends CrudRepository<InBodyBCA, Long> {
#Query(value = "SELECT * FROM in_body_bca bca WHERE person_id = :personId " +
"AND to_timestamp(bca.datetimes::text, 'YYYYMMDDHH24MISS') BETWEEN :startRange AND :endRange",
nativeQuery = true)
List<InBodyBCA> findAllByPersonId(#Param("personId") Long personId,
#Param("startRange") LocalDateTime startRange,
#Param("endRange") LocalDateTime endRange);
But in PgAdmin the query works fine
SELECT id, to_timestamp(datetimes::text, 'YYYYMMDDHH24MISS') as dt FROM in_body_bca WHERE to_date(datetimes::text, 'YYYYMMDDHH24MISS')
BETWEEN '2018-05-07' AND '2019-05-07' ORDER BY to_date(datetimes::text, 'YYYYMMDDHH24MISS') DESC ;
You use the double colon here: bca.datetimes::text. JPA would look for text variable name.
You need to escape it:
bca.datetimes\\:\\:text

Use postgres function timestamp in JpaRepository

I try to group by date only, column active_to is timestamp so it has time also. This query works in pgAdmin but JpaRepository seems to have problem even if it is native query. How can I modify this query to work using JpaRepository?
#Query(value = "SELECT o.active_to::timestamp::date, count(o) as sum from work_order o group by o.active_to::timestamp::date order by o.active_to::timestamp::date asc limit 7", nativeQuery = true)
I get this error:
org.postgresql.util.PSQLException: ERROR: syntax error at or near ":"
Position: 19
You cannot use : because this is the character that starts a named parameter.
You have to use cast.
#Query(value = "SELECT cast(cast(o.active_to as timestamp) as date), count(o) as sum " +
"from work_order o group by cast(cast(o.active_to as timestamp) as date) " +
"order by cast(cast(o.active_to as timestamp) as date) asc limit 7",
nativeQuery = true)
Cast and :: are similar. Read more about here:
https://www.postgresql.org/docs/current/sql-expressions.html#SQL-SYNTAX-TYPE-CASTS

Not a Valid Month in Hibernate

Hi im trying to get number of rows from table using Hibernate based on start and end Date but im Getting not a Valid Month error
Session session = sessionFactory.getCurrentSession();
startDate = "13-02-02 00:00:00";
endDate = "17-02-02 00:00:00";
try{
String hql = "select Count(*) from mytable where PERIOD_START_DATETIME between '"
+ startDate + "' AND '" + endDate + "'";
Query query = session.createQuery(hql);
long count=(long) query.uniqueResult();
return count;
} finally{
session.close();
}
This is my table description
Name NULL TYPE
NAME NOT NULL VARCHAR2(255 CHAR)
PERIOD_END_DATETIME NOT NULL TIMESTAMP(6)
PERIOD_START_DATETIME NOT NULL TIMESTAMP(6)
PROD_OFFER_TERM_TYPE_ID NOT NULL NUMBER(19)
Using string concatenation for generating SQL queries is usually a bad idea because
it's bad for performance (causes re-parsing of the SQL statement for every execution)
it's prone to SQL injection attacks
HQL supports bind variables / prepared statements, so this should work:
String hql = "select Count(*) from mytable where PERIOD_START_DATETIME between :startdate AND :enddate ";
Query query = session.createQuery(hql);
query.setParameter("startdate", startDate);
query.setParameter("enddate", endDate);
(where startDate and endDate are actual java.sql.Timestamp values, not strings).
As the start/end times are SQL TIMESTAMPs in the DB, you can pass in a Timestamp object into the query as follows:
Session session = sessionFactory.getCurrentSession();
final DateFormat df = new SimpleDateFormat("yy-MM-dd");
// omitting the time part will set the time to midnight (00:00:00)
Timestamp start = new Timestamp(df.parse("13-02-02").getTime());
Timestamp end = new Timestamp(df.parse("17-02-02").getTime());
try {
String hql =
"select Count(*) from mytable where PERIOD_START_DATETIME between ? AND ?";
Query query = session.createQuery(hql)
.setTimestamp(0, start)
.setTimestamp(1, end);
long count = (long) query.uniqueResult();
return count;
} finally {
session.close();
}
Make sure you actually pass date values in your query.
You can use the to_date function where you specify the format of the date, as it is represented in the string.
select Count(*)
from mytable
where PERIOD_START_DATETIME between to_date(startDate,'DD-MM-YYYY HH24:MI:SS') AND to_date(endDate,'DD-MM-YYYY HH24:MI:SS');
select Count(*)
from mytable
where PERIOD_START_DATETIME between TO_TIMESTAMP(:startDate, 'YY-MM-DD HH24:MI:SS') AND TO_TIMESTAMP(:endDate, 'YY-MM-DD HH24:MI:SS')

Java native SQL query to display all values when an input param is null

I have the following DAO method:
public String getSomeTable(final String param1) {
String sqlString = "select * from table where name ilike ?";
Query query = this.getEntityManager().createNativeQuery(sqlString);
query.setParameter(1, "%param1%");
}
If param1 is null or empty then I want to select all entries from the table. What is the correct way to do this? I am currently using the following:
public String getSomeTable(final String param1) {
String sqlString = "select * from table where name = ?";
Query query = this.getEntityManager().createNativeQuery(sqlString);
if(param1 == null)
query.setParameter(1, "%%");
else
query.setParameter(1, "%param1%");
}
But this is not scalable. I have datatypes like integer, date, etc. I want to know if there is a way to skip checking for that parameter if it is null.
I was planning to use COALESCE(?, CASE WHEN ? = '' THEN '%%' ELSE '%?%') but I think ? can be used only once for a particular parameter. The next one > I write is linked to second param.
On SQL Server, I use something like this, perhaps you can translate it to postgres:
DECLARE #variable INT = NULL;
SELECT *
FROM sysobjects
WHERE
(1 = CASE WHEN #variable IS NULL THEN 1 ELSE 2 END)
OR
(id LIKE #variable);

Return a boolean from a JpaRepository method

I have a native query in an interface which extends JpaRepository. The method should ideally return a boolean value, but I can't figure out how to SELECT anything that gets automatically translated into boolean.
This works, although I have to call it as Boolean.valueOf(hasKids(id)):
// yuck. I wanted a boolean
#Query(nativeQuery = true, value = "select 'true' from dual where exists("
+ "select * from child_table where parent_id = ?)")
String hasKids(long parentId);
How can I change this to the more natural return type?
boolean hasKids(long parentId); // throws ClassCastException
Update:
the stacktrace is not very helpful IMHO because it's the usual nightmare of Hibernate proxies and AspectJ closures, but here's the relevant portion anyway.
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
at com.sun.proxy.$Proxy1025.hasKids(Unknown Source)
at com.bela.foo.bar.Service.ThingyServiceImpl.recordHasKids_aroundBody4(ThingyServiceImpl.java:85)
at com.bela.foo.bar.Service.ThingyServiceImpl$AjcClosure5.run(ThingyServiceImpl.java:1)
...
I ran into a similar problem. My solution was to use a projection of java.lang.Boolean.
#Query("select new java.lang.Boolean(count(*) > 0) from child_table where parent_id = ?")
Boolean hasKids(long parentId);
Hope this helps someone.
I think you want to check the row exist or not for the parent id,and return true and false on the basis of that, then go for the case.
Changes to made in query
"select case when (count(*) >0) then true else false end from dual where exists("
+ "select * from child_table where parent_id = ?)
I tested this by removing the single quotes around true and it works.
#Query(nativeQuery = true, value = "select true from dual where exists("
+ "select * from child_table where parent_id = ?)")
String hasKids(long parentId);
With my Oracle constraint and a combination of all the suggestions here, I found a solution that worked for my situation without having to call Boolean.valueOf(hasKids(id)):
#Query(nativeQuery = true, value = "select case when exists(select * from child_table "
+ "where parent_id = :parentId) then 'true' else 'false' end from dual")
Boolean hasKids(#Param("parentId") long parentId);
There seems to be an issue, at least with mysql
(count() >0) convert to boolean fine when the query is non native
(count() >0) returns a "BigInteger cannot be cast to java.lang.Boolean" when the query is native

Categories