I've got an application that uses a hibernate(annotations)/mysql combination for ORM. In that application, I got an entity with a Date field. I'm looking for a way to select on that date within a time range (so hh:mm:ss without the date part).
In MySQL there's a function TIME(expression) that can extract the time part and use that in the where clause, but that does not seem to be available in Hibernate without switching to native queries. Is there an option in hibernate to do this, or should I loop through the results in java and do the comparison there? Would this be much slower as the MySQL solution, since that would not use indexes anyway?
The following functions are available in HQL, maybe you could use them:
second(...), minute(...), hour(...), day(...), month(...), year(...)
Add the expression as a SQL restriction rather than having a full native query. I don't know MySQL specifically, but imagine something like this:
Criteria criteria = session.createCriteria(MyTable.class);
criteria.add(
Expression.sql(
"TIME( {alias}.my_date, 'hh:mm:ss') >= :1",
dateRangeMin,
new StringType()
)
);
Related
So, I need to translate the following query into Java
SELECT * FROM table WHERE TIME(date) BETWEEN TIME(startTime) AND TIME(endTime)
where date is a datetime column. Both startTime and endTime are local variables.
The technologies that I'm using right now are Spring and Hibernate.
The following solution
query.add(
Restrictions.sqlRestriction(
"TIME(date) between TIME('?') and TIME('?')", values, types
);
, where the values variable is an array with startTime and endTime and the types variable is an array with the values's respective types (string), unfortunately is not compatible with H2, since the TIME function wasn't implemented. I do know that the HOUR, MINUTE and SECOND functions are implemented and working.
I haven't figured out a way of implementing it myself and couldn't find any solution online. Does anyone have any idea of how I can overcome this?
If you read through the HQL language specification, you will find that it is largely devoid of any support for date/time functions. This is mainly due to that every database has its own way of handling date and time, so there is little common support. However, the CAST function is supported by HQL, assuming the underlying database also supports it. From the H2 documentation, we find this example of casting to time:
CAST(TIMESTAMP '2010-01-01 10:40:00.123456' AS TIME(6))
So, you may try doing this in your HQL query:
SELECT *
FROM table
WHERE
CAST(date AS TIME(6)) BETWEEN CAST(startTime AS TIME(6)) AND
CAST(endTime AS TIME(6));
I'm new to hibernate framework and I don't know how to write code using hibernate functions to get needed object. In internet I have seen code using criteria and projection, but the query for projection is not what i need. For example i need to get last version of project by date. This is criteria
Criteria criteria = session
.createCriteria(Assembly.class)
.setProjection(Projections.max("date"));
-First problem is that it gets max value from all table(don't know how to set for searching only exact project name date).
-Second problem that it returns date but i need object of class.
In summary i need from hibernate to generate such query:
SELECT * FROM assembly WHERE projectName = ? AND ...don't know how to finish it, date = max() - won't work as I understand.
One of the bad solution is to get all exact projects and then compare there dates, but I think there's gonna be good solution.
This should work
Assembly newest =
(Assembly) session.createCriteria(Assembly.class)
.add(Restrictions.eq("projectName", projectName))
.addOrder(Order.desc("date"))
.setMaxResults(1)
.uniqueResult();
I am filtering a search with criteria object.
but the filter doesn't work for date.
I made this for instance :
criteria.add(Restrictions.and(
Restrictions.like("serialNumber", device.getSerialNumber()),
Restrictions.like("installDate", device.getInstallDate()), // a date
Restrictions.like("ipAdress", device.getIpAdress())));
then i made this :
else if (device.getInstallDate() != null) {
criteria.add(Restrictions.like("installDate", device.getInstallDate()));
}
Do you have any idea to filter by date ?
Your code/approach looks fine. You may want to enable SQL logging to see what statements exactly are sent to the DB and what values are bound to the statement parameters. This should help you figure out the issue (the issue may be just some detail like e.g. dates with/without time parts, or something similar).
See also:
Hibernate show real SQL
To search for exact dates I use:
criteria.add(Restrictions.eq("installDate", device.getInstallDate()));
Note also that dates and timestamps are treated differently by the underlying database based on the corresponding SQL types. A field declared as a date will not include hours/minutes/etc. If the desire is to compare both date and time, be sure to use timestamp in the Hibernate declaration.
The fastest way to show the SQL statements is to set the show_sql property to true in your Hibernate configuration
Is it possible to do a date query in JDOQL without using a parameterrised query on Google App Engine.
I am trying to write some generic code that looks something like this, where criteria is just a string, and I would like to be able to specify anything - with this piece of code not needing to to know much about the underlying data.
Query query = pm.newQuery(tClass);
if (criteria!=null) {
query.setFilter(criteria);
}
criteria could be "startdate = 'someproperlyformatteddatetime'"
Thanks for your suggestions.
Of course, GAE JDO queries support JDOQL. You could simply do something like this: q.setFilter("height <= 200") or q.setFilter("name == 'Smith'"), where you would programmatically assemble the JDOQL filter string. The only downside is that you need to know the type of parameters (as saved in Datastore), as strings need to be enclosed in single or double quotes.
Note that all restrictions on queries still apply.
Also, if you want to query on multiple properties where you also use inequality operator, then you need to define compound indexes beforehand.
Update: JDOQL literal parameter specification works with string and numeric values; all other value types must use parameter substitution. You could still do that programmatically.
Another workaround would be if you use long instead of Date and convert dates to UNIX timestamps (which are of type long).
I am using the CriteriaBuilder and CriteriaQuery to build my query to the database, but I have encountered an issue that I do not know how to solve, since I am very new to this whole ordeal called JPA.
In Java, I have a property called timestamp for a class called Report, and it is set to the same corresponding #TemporalType.
I also have a class called Affiliate which has a list of Report objects.
In my query, I want to fetch all the Affiliate objects that do not have a Report in the last Affiliate.maxSilenceMinutes.
My questions:
Are there any ways in standardized JPA to modify dates? Like a CriteriaBuilder.subtractMilliseconds(Expression<Timestamp>, Long) of sorts?
If not, is there a way to cast Expression<Timestamp> to Expression<Long> so that I can subtract on a currentTimestamp literal to get the minimum value for a CriteriaBuilder.lessThanOrEqualTo(greatestReportTimestampMs, minimumAllowedMs)?
I know this might feel like a confusing question, but the main part is simply: Is it possible to go Expression<Timestamp> to Expression<Long>? It throws an exception for me if I try to use the .as(Long.class) method, but which should be the default underlying data type in most DBs anyway?
Hope you guys can help, since I feel kind of stuck :)
If you know the value you want to subtract at the time of querying,
you can subtract beforehand:
Calendar c = new Calendar();
c.setTime(timestamp.getTimestamp());
c.add(DAY, - someNumberOfDays); //or whatever unit you want
Date d = c.getTime();
If not, you probably need to call a database function to do the subtraction, via
CriteriaBuilder.function()
CriteriaBuilder.lessThanOrEqual() works on Comparables. Timestamps are comparable. So you could construct a Timestamp via new Timestamp(long ms)
and compare it with the other expression.
I hope this helps.
This is not built into Hibernate, so you will need a custom function of some kind.
The JDBC standard includes a function escape {fn TIMESTAMPADD( SQL_TSI_SECOND, secs, timestamp)} which should be translated into the correct SQL for the target database, but not all JDBC implementations provide it. There is therefore a chance you can add a custom StandardJDBCEscapeFunction to Hibernate's Dialect to get the result you need.
If you don't have that available, you'll have to find out what the correct database specific implementation is and there is a lot of variability here. For example:
Oracle: (timestamp + secs/86400)
SQLServer: DATEADD(ss,secs,timestamp)
DB2: (timestamp + secs SECONDS)
MySQL: DATE_ADD(timestamp, INTERVAL secs SECONDS)
Once you know it, you can use the correct expression as an SQL criteria.
The fact that date-time manipulation is not standardised in the Dialect and not fully implemented in many JDBCs means that what you are trying to do will be very difficult to write in a database neutral way.