java criteria Date comparison - java

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

Related

On Google App Engine is it possible JDOQL Date without using a parameterised query?

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).

How to process 0000-00-00 date in jdbc MySQL query

I'm getting this exception:
java.sql.SQLException: Value '0000-00-00' can not be represented as java.sql.Date
Originating from this code:
Date internalDate = rs.getDate(idx++);
Where rs is a ResultSet.
So this is fine to me - I know there are zero'ed dates in the database and I need to be able to read these and convert them into an appropriate (probably null) data in my downstream data structures. The problem is I don't know how to retrieve it and get a "soft" error. I thought about wrapping this line in a try/catch for SQLException but understand this will break validity of the ResultSet.
Is it possible to read this value in another way without throwing a SQLException?
I like #a_horse_with_no_name's answer, however if you don't have control over the connection, you could change the query to return a null instead:
select
...
case when my_date_col = '0000-00-00' then null else my_date_col end as my_date_col,
...
or the slightly more terse, but mysql-only, option:
if(my_date_col = '0000-00-00', null, my_date_col) as my_date_col
Also, caution is advised changing the entire application's JDBC behaviour as you may break code that relies on such dates being returned - perhaps they use rs.getString(i) instead. You would have to regression test all other queries to be sure.
You need to tell the JDBC driver to convert them to NULL. This is done by passing a connection property name zeroDateTimeBehavior with the value convertToNull
For more details see the manual: http://dev.mysql.com/doc/refman/4.1/en/connector-j-installing-upgrading.html
I suggest using rs.getString() and parsing the String yourself. If it is all 0s, then use a null Date reference. If not, create an appropriate Date object.
Set the column Allow Null, and Set Default Value at Column : 1900-01-01 was my best solution...
Convert this String result to a date by using "simpleDateFormat.parse(yourValue)"
Get day or year or month value from that date ( whichever you want)
This will return int value
Check if it is 0
If it is zero set date equal to null.

'0000-00-00 00:00:00' can not be represented as java.sql.Timestamp error

I have a database table containing dates
(`date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00').
I'm using MySQL. From the program sometimes data is passed without the date to the database. So, the date value is auto assigned to 0000-00-00 00:00:00
when the table data is called with the date column it gives error
...'0000-00-00 00:00:00' can not be represented as java.sql.Timestamp.......
I tried to pass null value to the date when inserting data, but it gets assign to the current time.
Is there any way I can get the ResultSet without changing the table structure?
You can use this JDBC URL directly in your data source configuration:
jdbc:mysql://yourserver:3306/yourdatabase?zeroDateTimeBehavior=convertToNull
Whether or not the "date" '0000-00-00" is a valid "date" is irrelevant to the question.
"Just change the database" is seldom a viable solution.
Facts:
MySQL allows a date with the value of zeros.
This "feature" enjoys widespread use with other languages.
So, if I "just change the database", thousands of lines of PHP code will break.
Java programmers need to accept the MySQL zero-date and they need to put a zero date back into the database, when other languages rely on this "feature".
A programmer connecting to MySQL needs to handle null and 0000-00-00 as well as valid dates. Changing 0000-00-00 to null is not a viable option, because then you can no longer determine if the date was expected to be 0000-00-00 for writing back to the database.
For 0000-00-00, I suggest checking the date value as a string, then changing it to ("y",1), or ("yyyy-MM-dd",0001-01-01), or into any invalid MySQL date (less than year 1000, iirc). MySQL has another "feature": low dates are automatically converted to 0000-00-00.
I realize my suggestion is a kludge. But so is MySQL's date handling.
And two kludges don't make it right. The fact of the matter is, many programmers will have to handle MySQL zero-dates forever.
Append the following statement to the JDBC-mysql protocol:
?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
for example:
jdbc:mysql://localhost/infra?zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=UTF-8&characterSetResults=UTF-8
Instead of using fake dates like 0000-00-00 00:00:00 or 0001-01-01 00:00:00 (the latter should be accepted as it is a valid date), change your database schema, to allow NULL values.
ALTER TABLE table_name MODIFY COLUMN date TIMESTAMP NULL
As an exteme turnaround, when you cannot do an alter to your date column or to update the values, or while these modifications take place, you can do a select using a case/when.
SELECT CASE ModificationDate WHEN '0000-00-00 00:00:00' THEN '1970-01-01 01:00:00' ELSE ModificationDate END AS ModificationDate FROM Project WHERE projectId=1;
you can try like This
ArrayList<String> dtlst = new ArrayList<String>();
String qry1 = "select dt_tracker from gs";
Statement prepst = conn.createStatement();
ResultSet rst = prepst.executeQuery(qry1);
while(rst.next())
{
String dt = "";
try
{
dt = rst.getDate("dt_tracker")+" "+rst.getTime("dt_tracker");
}
catch(Exception e)
{
dt = "0000-00-00 00:00:00";
}
dtlst.add(dt);
}
I wrestled with this problem and implemented the URL concatenation solution contributed by #Kushan in the accepted answer above. It worked in my local MySql instance. But when I deployed my Play/Scala app to Heroku it no longer would work. Heroku also concatenates several args to the DB URL that they provide users, and this solution, because of Heroku's use concatenation of "?" before their own set of args, will not work. However I found a different solution which seems to work equally well.
SET sql_mode = 'NO_ZERO_DATE';
I put this in my table descriptions and it solved the problem of
'0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
There was no year 0000 and there is no month 00 or day 00. I suggest you try
0001-01-01 00:00:00
While a year 0 has been defined in some standards, it is more likely to be confusing than useful IMHO.
just cast the field as char
Eg: cast(updatedate) as char as updatedate
I know this is going to be a late answer, however here is the most correct answer.
In MySQL database, change your timestamp default value into CURRENT_TIMESTAMP. If you have old records with the fake value, you will have to manually fix them.
You can remove the "not null" property from your column in mysql table if not necessary. when you remove "not null" property no need for "0000-00-00 00:00:00" conversion and problem is gone.
At least worked for me.
I believe this is help full for who are getting this below Exception on to pumping data through logstash
Error: logstash.inputs.jdbc - Exception when executing JDBC query {:exception=>#}
Answer:jdbc:mysql://localhost:3306/database_name?zeroDateTimeBehavior=convertToNull"
or if you are working with mysql

Java Persistence Criterias; Cast Expression<Timestamp> to Expression<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.

Compare time part of datetime field in Hibernate

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()
)
);

Categories