Older then query in java persistence - java

I need to do a query where i take things older then 5 days.(a custom date)
i have looked at HQL but since it is in persistence i dont have access to setTimestamp as per here
String hqlQuery;
Calendar minDate = Calendar.getInstance();
minDate.add(Calendar.DATE, -days);
hqlQuery = "select n from notifications where n.app_id=:app and ((n.sent_date<=:minDate) OR (n.sent_date is null)) and n.handled='N'";
is how i tried...
Any sweet helpers, thanks in advance :-)
Edit:
So i changed my method it now looks like this:
public static List<Notification> findOlderThen(EntityManager em, Long app, int days) {
String hqlQuery;
Calendar minDate = Calendar.getInstance();
minDate.add(Calendar.DATE, -days);
hqlQuery = "select n from notifications where n.app_id=:app and ((n.sent_date<=:minDate) OR (n.sent_date is null)) and n.handled='N'";
System.out.println(hqlQuery);
return em.createQuery(hqlQuery).setParameter("app", app).setParameter("minDate",minDate.getTime()).getResultList();
}
But it gives this error:
Caused by: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Syntax error parsing the query [select n from notifications where n.app_id=:app and ((n.sent_date<=:minDate) OR (n.sent_date is null)) and n.handled='N'], line 1, column 28: syntax error at [where].
Internal Exception: UnwantedTokenException(found=where, expected 80)

SessionFactory sf = // get your session factory
Query q = sf.getCurrentSession()
.createQuery(hqlQuery);
q.setParameter("minDate",minDate.getTime())
.setParameter("app", appId)
.list();
Would be how you set a date parameter, assuming type of sent_date is Date in Notifications model class. Also, on this part of your query select n from notifications, make sure notifications is the actual name of your class. Case matters! It should probably be select n from Notifications n.
Update:
You need to declare the alias for the class.

If I'm not mistaken, aren't you supposed to do something like this when you're adding dates in a query:
hqlQuery = "select n from notifications where n.app_id=:app and ((n.sent_date<=':minDate') OR (n.sent_date is null)) and n.handled='N'";
notice the ' around the minDate variable

Related

How to use ::date in java JDBC hibernate?

PG Admin
I have a query on SQL Editor in PGadmin:
select * from list_taxi where last_update::date = now()::date
It show a good result, It show the taxi that online/update today.
(I use ::date).
Then I implement the query into Java using hibernate.
Java - JDBC Hibernate
I have a timestamp variable
Timestamp nowTime = new Timestamp(System.currentTimeMillis() );
I have query in Java DAO connected to Postgresql (JDBC - Hibernate)
ArrayList<Object[]> arrayList =
(ArrayList) em.createQuery("SELECT lt FROM ListTaxi lt
WHERE lt.lastUpdate::date = '" + nowTime + "'::date ")
.getResultList();
The result is error because of ::date
java.lang.IllegalArgumentException:
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:
: near line 1, column 75 [SELECT lt FROM model.ListTaxi lt WHERE
lt.lastUpdate::date = lt.lastUpdate::date]
How to solve this?
As a workaround you can do
WHERE lastUpdate > :startOfTodayTimestamp -- set this to :00:00:00 today
If you have dates from the future or want to do this not just with today, you also need to add an upper bound.

Hibernate: using LocalDateTime to query a range

I'm using hibernate 5 with the hibernate-java8 addon to use LocalDateTime fields. I now have an entity which has a date field and a user field like in:
#Entity
public class Transaction {
// ...
private User user;
private LocalDateTime date;
// ..
}
Now I simply want to query all transactions of a user within a certain time range. So I use the following query:
SELECT t FROM Transaction t WHERE t.user = :owner AND t.date BETWEEN :from AND :to
Strange enough this query does not give me any results. I also tried using the < and > operators but that did not help either. When I leave out the time range part I get the correct list of transactions for the user. When I execute the SQL query generated by Hibernate in the MySQL workbench I also get the expected results. I use the following snippet to execute the (named) query:
public <T> List<T> findList(Class<T> type, String queryName,
Map<String, Object> params) {
final EntityManager em = this.entityManager.get();
final TypedQuery<T> query = em.createNamedQuery(queryName, type);
params.forEach(query::setParameter);
return query.getResultList();
}
This is simply called providing the query listed above and a map of named parameters like:
findList(Transaction.class, Transaction.BY_USER_AND_RANGE,
ImmutableMap.of("owner", owner, "from", from, "to", to));
In my test case a persisted a single Transaction with the current date and created a range from yesterday to tomorrow for the query. Inspecting the table in the MySQL workbench shows that the transaction is there and that the date field has the correct type and contains the correct value. Yet my query won't give me any results.
Is there anything I'm missing?
The date you are passing as param should also be
LocalDateTime
see the example code below might help you
LocalDate date = LocalDate.of(2015, 8, 11);
TypedQuery<MyEntity> query = this.em.createQuery("SELECT e FROM MyEntity e WHERE date BETWEEN :start AND :end", MyEntity.class);
query.setParameter("start", date.minusDays(2));
query.setParameter("end", date.plusDays(7));
MyEntity e = query.getSingleResult();

JPA query equivalent to mysql query

Below is mysql query which is working fine and giving me expected results on mysql console.
select * from omni_main as t where t.date_time BETWEEN STR_TO_DATE(CONCAT('2011', '08', '01'),'%Y%m%d') AND LAST_DAY(STR_TO_DATE(CONCAT('2012', '08','01'), '%Y%m%d')) group by year(date_time),month(date_time)
I need its JPA equivalent query. Below is what I am trying but its returning nothing.
String queryStr = "select * from OmniMainEntity o where o.dateTime BETWEEN STR_TO_DATE(CONCAT('"+fromYear+"', '"+fromMonth+"','01'), '%Y%m%d') AND "
+"LAST_DAY(STR_TO_DATE(CONCAT('"+toYear+"', '"+toMonth+"','01'), '%Y%m%d'))";
Query query = manager.createQuery(queryStr);
System.out.println("Result Size: "+query.getResultList().size());
Here fromYear, fromMonth, toYear, toMonth are method parameters using in creating queryStr.
Please suggest where I may wrong!
Any other way to achieve goal is also welcome!
As you are using JPA Query, it would be better to not use database-specified sql function, such as STR_TO_DATE.
You can have a try by this way.(A Hibernate way, JPA should be similiar):
First, you can parse a java.util.Date object from "fromYear" and "fromMonth" like below:
DateFormat df = new SimpleDateFormat("yyyyMMdd");
Date startDate = df.parse(fromYear + "" + fromMonth + "01");
Date endDate = df.parse(.....);
Then, set them into the JPA query.
String queryStr = "select * from OmniMainEntity o where o.dateTime BETWEEN :startDate AND :endDate)"; // The query now changed to database independent
Query query = manager.createQuery(queryStr);
query.setDate("startDate", startDate);
query.setDate("endDate", endDate);
At last, doing the search:
System.out.println("Result Size: "+query.getResultList().size());
Your query doesn't have a verb in it. You probably want SELECT in there:
SELECT o FROM OmniMainEntity o WHERE...
Also, you should be using parameterized and typed queries, and it's usual to use short names (o instead of omniMainEnt) to make your queries readable.

fetch records based on today's date

I wish to generate reports for my application, one such report requires to display list of orders given today. For that I have the following method in my ejb which returns nothing (debugged and found so):
public Collection<OrderStock> getOrderReport(String userName) {
String strQuery = null;
strQuery = "Select o from OrderStock o where o.userName.userName = :userName and o.orderDateTime = :orderDateTime";
Collection<OrderStock> c = em.createQuery(strQuery).setParameter("userName",userName).setParameter("orderDateTime", new Date(),TemporalType.DATE).getResultList();
return c;
}
How do i solve it? Why does it return nothing?
edited:
I am using mysql as backend
datatype of orderDateTime is DateTime
eg os data in orderDateTime : 2012-06-05 00:12:32
2012-06-05 11:34:42
2012-04-05 12:32:45
You have a DateTime column, and are looking for posts on a single date. I suspect this datetime column contains seconds or miliseconds since the Epoch. You can't compare times to dates, so you will have to convert the day to a time. Actually two times that describe the day.
SELECT o
FROM OrderStock o
WHERE
o.userName.userName = :userName
AND (
o.orderDateTime >= FirstSecondOfTheDay
OR o.orderDateTime <= LastSecondOfTheDay
)
Depending on your database system you can calculate these seconds (or milliseconds, i don't know your table) using the database or rather do it in java
You can not use Date() as simple as that. The date persisted in the DB will definitely have different format. So the best thing to do is to look into the method used to persist the data in the first place and use the same method to fetch back the data.
The method might by Oracle function, java method. You need to investigate further into this.
Try this for MySQL:
strQuery = "Select o from OrderStock o where o.user.userName = :userName and date(o.orderDateTime) = :orderDateTime";
Date today = DateUtils.truncate(new Date(), Calendar.DATE);
Collection<OrderStock> c = em.createQuery(strQuery).setParameter("userName",userName).setParameter("orderDateTime", today ,TemporalType.DATE).getResultList();

Write HQL clause using Hibernate Criteria API

I want to write a method that returns a list of last added objects grouped by field 'serviceId'.
The following HQL works, but I want to write this using Criteria API:
FROM Notification WHERE date IN
(SELECT MAX(date) FROM Notification GROUP BY serviceId)
ORDER BY date ASC
Something like this:
Criteria crit = session.createCriteria(Notification.class);
crit.add(Restrictions.in("date", <MAX dates>));
criteria.addOrder(Order.desc("date"));
Thanks in advance.
EDIT:
Now I need a similar query that works using eclipselink API =/
Basically, I need the last N rows (max date), which status is one of the five described bellow, grouped by serviceId column.
Due to my inexperience, it was the best I could:
ExpressionBuilder builder = new ExpressionBuilder();
Expression exStatus1 = builder.get("status").equal(MessageType.START.toString());
Expression exStatus2 = builder.get("status").equal(MessageType.RUNNING.toString());
Expression exStatus3 = builder.get("status").equal(MessageType.PAUSED.toString());
Expression exStatus4 = builder.get("status").equal(MessageType.END_ERROR.toString());
Expression exStatus5 = builder.get("status").equal(MessageType.END_SUCCESS.toString());
ReadAllQuery query = new ReadAllQuery();
query.setReferenceClass(Notification.class);
query.setSelectionCriteria(((exStatus1).or(exStatus2).or(exStatus3).or(exStatus4).or(exStatus5)));
query.setMaxRows(listSize);
query.addDescendingOrdering("date");
The clause to avoid duplicates serviceIds in result rows is missing...
You're going to want to use the Criteria projections API with a detached subquery:
Criteria crit = session.createCriteria(Notification.class, "main");
DetachedCriteria notificationSubQuery = DetachedCriteria.forClass(Notification.class, "sub");
notificationSubQuery.setProjection(Projections.max("date"));
notificationSubQuery.add(Restrictions.eqProperty("sub.serviceId", "main.serviceId"));
crit.add(Subqueries.propertyIn("date", notificationSubQuery));
crit.addOrder(Order.desc("date"));
This mirrors the technique you are using in your HQL query.
EDIT:
I updated the query to match serviceId between your main notification class and your sub query, essentially the same as this HQL Query:
FROM Notification main WHERE date IN
(SELECT MAX(sub.date) FROM Notification sub WHERE sub.serviceId = main.serviceId)
ORDER BY date ASC
This prevents the case where you would have a non-maximum date matching between two different serviceIds like so:
serviceId = 1: date = 3,4,5
serviceId = 2: date = 4,5,6
Old query return:
serviceId: 1, date: 5
serviceId: 2, date: 5,6
New query return:
serviceId: 1, date: 5
serviceId: 2, date: 6
Let me know if this works for you.

Categories