Hibernate: how to get time gap between two Date columns? - java

For example, my columns look like
1990-02-13 00:00:00.0 and 2015-02-19 00:00:00.0.
How can I get the time gap (difference) in days?

If you are using MySQL dialect for Hibernate you can use the following functions,
unix_timestamp(datetime_value) - to take the difference between two columns
current_date() to get the current date.
a list of reference functions could be found here
https://hibernate.atlassian.net/secure/attachment/11953/MySQLDialect.java
For the second question can you try using
criteria.add( Restrictions.le("date_column", current_date() ) )

Related

SQL Query to retrieve list of a field between two dates

I have a table in which there are two columns namely startTime and endTime (both are DateTime dataTypes) there is another column 'Duration' which calculates the difference between these two. I want to retrieve Duration between specific dates like June10-June20. The problem is I've many rows for same date and Few dates between the range dont even exist. I need to plot the graph for the specified range. So, I have to append zero to the output when there is no entry for a particular day and the similar day's value has to be added together and returned as a single value. So, the output rows should be equal to the number of days specified.
Click here for Example
Thanx in advance.
Assuming that the start and end dates in every row would differ only in the time component.
Also assuming that you do not have any other table that has dates listed and you need a dynamic table to list all the dates between the given range.
You could do the following.
select list_of_dates.date, ifnull(sum(your_table.duration),0)
from your_table
right join
(SELECT DATE(ADDDATE('2016-06-20', INTERVAL #i:=#i+1 DAY)) AS date
FROM your_table,
(select #i:=-1) local
HAVING
#i < DATEDIFF('2016-06-25', '2016-06-20') ) list_of_dates
on list_of_dates.date = date(your_table.start_date)
group by list_of_dates.date
If you have a table that stores relevant calendar it gets easier
select calendar_table.date, ifnull(sum(your_table.duration),0)
from your_table
right join
calendar_table
on calendar_table.date = date(your_table.start_date)
where calendar_table.date >= '2016-06-20' and calendar_table.date <= '2016-06-25'
group by calendar_table.date

Using Hibernate's Restrictions.ilike() on a Timestamp

I've been thinking it over, and I'm starting to wonder if this is even possible.
User Perspective:
There's a table of data, and one column contains a date. The user can type in a search term like dec and get all rows that occurred during December.
Backend: A jqGrid is used for displaying the table. It sends the entered search terms to the server. The server uses the code
Criteria cr = session.createCriteria( DetailedLogEntry.class );
Disjunction disjunction = Restrictions.disjunction();
MatchMode matchMode = MatchMode.ANYWHERE;
disjunction.add( Restrictions.ilike( searchKey.getField(), searchKey.getData(), matchMode ) );
cr.add( disjunction );
to apply the search terms, and where DetailedLogEntry contains a Date variable to represent the database's TIMESTAMPfield.
Because searchKey.getData() returns a string, comparing it against a date object results in an empty set.
So I guess the question is...is it possible, preferbly through Hibernate, to apply a restriction against a Date object as if it were a String?
That's not possible. You'd need to use Restrictions.between() and give it an upper and lower date values. You could use SimpleDateFormat to convert from your String values to Date values and then perform the search?
If the user searched for Dec, would you expect all the log entries from December of every year to show up? Can they type in :"1, Dec" and expect to see all the logs from the 1st December for every year? If it is string matching on dates you are looking for, it might be easier to load all the data into your jqGrid and use javascript to filter the table based on the string formatted date values.

Get distinct months from database using HQL

I have a java.util.Date field in an #Entity and would like to get the distinct months from that column.
Suppose I only had three rows, with 14/07/2010, 24/11/1975 and 03/11/1975 (European date format - day/month/year), I would like to get the following back from Hibernate to go into a dropdown for filtering the data:
07/2010
11/1975
(or corresponding Date objects with the other fields set to zero - to be honest precisely how the data comes back isn't too important as I can work around that).
I'm guessing a database-agnostic approach in HQL isn't possible - any suggestions?
What about :
select distinct month(c.birthday), year(d.birthday) from Cat c

Query by age in hql

I have a class User with one field called birthDate which is a java.sql.Date.
How do I do a hql query that will retrieve all Users that are between min and max years old?
(My real scenario is slightly more complex than that but that's where I am stuck right now).
UPDATE
It must be an hql expression so I can put the age expression in a computed property.
Calculate the birth dates corresponding to the min and max ages. Then use the below HQL.
Select u from User u where u.birthDate between :minDate and :maxDate
Setup the the minDate and maxDate to the values you computed before executing the query.
It depends on the database. Most have some way of handling date arithmetic. MySQL has a datediff function that will return a number of days so you could divide that by 365 and get pretty close. The MySQL dialect already has datediff as a registered function. For other databases you may need to use different functions and possibly register them in a custom dialect. But you may be off by a little unless you take leap years into account which is tricky in an HQL expression. Using dates is easier because you can keep the month and day constant, change the year, and then use < or > in HQL.

Index on date type column in oracle not used when query is run from java

i have a table containing 15+ million records in oracle. its sort of a log table which has a created_ts column of type "date" . i have a simple "non-unique" type index on created_ts column.
i have a simple range query :
select * from table1 where created_ts >= ? and created_ts <= ?;
when i run this query from SQLPlus or SQL Developer etc like this :
select * from table1
where created_ts >= TO_DATE( '2009-11-10 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
and created_ts <= TO_DATE( '2009-11-10 23:59:59', 'YYYY-MM-DD HH24:MI:SS');
the query returns within 1-2 second max.
but when I run the exact same query in java over JDBC and set the corresponding "?" params using java.sql.Timestamp object . the query takes long time . Analyzing the oracle process it goes for full table scan and doesnt use the index.
the jdbc driver i am using is ojdbc5 11.1.0.7.0
Can any one please help .. how to create the index correctly so that it uses the index.
My problem was resolved when i used "oracle.sql.DATE" objects to set the bind variables instead of "java.sql.timestamp" . The query used the index and executed almost within 1-2 seconds.
Thanks to all who replied and helped.
But its problematic for me as this solution is DB dependent and my app receives DB connection and query as param and load and process data in a generic way. The DB connection can be of any RDBMS like oracle, mysql, etc.
This is classic behaviour for an implicit datatype conversion. Because the database is having to convert the datatype of the column it cannot use any index on that column.
In your case I suspect this is due to your use of java.sql.Timestamp. Would it be possible to use the equivalent type from the Oracle datatypes package, oracle.sql.Timestamp? Obviously that may have some knock-on effects but I think you should at least test it, to see whether that solves your problem.
The difference may because of bind variables vs. literal values. You are not comparing the same things.
Try this in SQL*Plus:-
explain plan for
select * from table1 where created_ts >= :1 and created_ts <= :2;
set markup html preformat on
set linesize 100
set pagesize 0
select plan_table_output
from table(dbms_xplan.display('plan_table',null,'serial'));
This will show you the plan Oracle will pick when using bind variables. In this scenario, Oracle has to make up a plan before you have provided values for your date range. It does not know if you are selecting only a small fraction of the data or all of it. If this has the same plan (full scan?) as your plan from java, at least you konw what is happening.
Then, you could consider:-
Enabling bind peeking (but only after testing this does not cause anything else to go bad)
Carefully binding literal values from java in a way that does not allow SQL injection
Putting a hint in the statement to indicate it should use the index you want it to.
You should try a hint of the form /*+ USE_INDEX(table_name, index_name) */
My guess is that the optimizer is choosing a full table scan because it sees that as the best option in absence of knowing the bind values.

Categories