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

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.

Related

Compare date if not null

I need to find all the record with create date > X. X is a sql.Timestamp and might be null, in which case I want to just return all the records. So I tried: (createdAfter is Timestamp)
SELECT *
FROM sample AS s
WHERE s.isActive
AND (:createdAfter ISNULL OR s.insert_time > :createdAfter)
But all I'm getting is
org.postgresql.util.PSQLException: ERROR: could not determine data type of parameter $1
However, if I'll do the same query where I'm checking for an arbitrary int to be null:
SELECT *
FROM trades
WHERE (:sInt ISNULL OR trades.insert_time > :createdAfter )
Then it works. What's wrong?
There is no simple solution if you want to stick with native queries like that. The null value is converted to a bytea value. See for example this and this.
That value is quite hard to be casted or compared to a timestamp value.
The problem is not so much with the first comparison it would be handled by using coalesce, like:
COALESCE(:createdAfter) ISNULL
because there is no comparison beteween actual values and the data type does not matter. But the comparison
sometimestamp::timestamp > null::bytea (casts just to show the actual types so not working)
would need more logic behind maybe procedure & exception handling or so, not sure.
So if JPQL or CriteriaQueries are not possible for you have only bad options:
contruct the query by setting params by string concatenation or so (NOT! and not sure if realy works)
use PreparedStatement queries, more code & effort
also if using Hibernate, using session api like in this answer
You can try using the pg_typeof function, which returns a text string, and using a CASE statement to force which comparisons are made (otherwise there's no guarantee that postgres will short-circuit the OR in the correct order). You can then force the correct conversion by converting to text and then back to timestamp, which is inelegant but should be effective.
SELECT *
FROM sample AS s
WHERE s.isActive
AND
CASE WHEN pg_typeof( :createdAfter ) = 'bytea' THEN TRUE
WHEN s.insert_time > ( ( :createdAfter )::text)::timestamp THEN TRUE
ELSE FALSE
END

java criteria Date comparison

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

What is the default datatype for stmt.executeQuery(query)?

My oracle table employee has different datatype columns. For my purposes, I just need the data of each column as string. So, When I execute the below query, can I assume that date_of_birth (date datatype) will be returned as string.
...
rs = stmt.executeQuery("select * from employee");
...
rs.getString("date_of_birth");
...
Usually you can get data as string using ResultSets getString but it depends on jdbc driver.
But I would use recommended method from that table to retrieve column as it is always supported.
No you can't assume that.
You have to check your database columns types and use appropriate get methods based on that
e.g. getString(), getInt(), getDate() etc..
The datatype is probably java.sql.Timestamp, and yes if you call getString on it, you will get something, it will call toString on the timestamp value, you may not like the format of the date.
No, you cannot assume this. Most probably date_of_birth will be returned as java.sql.Date or some other date/time Java type (depending on the DB type, really).

unable to retrieve date from mysql into JDBC

the issue that i have at the moment is i cannot retrieve a date object from my mysql database, so far no matter what i try, i either get
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
or
java.sql.SQLException: Value '0000-00-00' can not be represented as java.sql.Date
does anyone have an idea regarding what can be done to solve this.
i have tried this and this but i still come to the same two errors which are both caused by the date
In addition to what the others have answered (including the very good advice that storing invalid dates is not a good idea) you can also instruct the JDBC driver to handle those invalid dates differently:
From: http://dev.mysql.com/doc/refman/5.5/en/connector-j-installing-upgrading.html
Connector/J 3.1 throws an exception by default when these values are encountered as this is the most correct behavior according to the JDBC and SQL standards. This behavior can be modified using the zeroDateTimeBehavior configuration property. The permissible values are:
- exception (the default), which throws an SQLException with an SQLState of S1009.
- convertToNull, which returns NULL instead of the date.
- round, which rounds the date to the nearest closest value which is 0001-01-01.
I would recommend to use convertToNull
See here for a description on how to specify configuration properties.
'0000-00-00' is an invalid date. It should not exist in your data.
Therefore, you need to either:
clean up the data and turn off allow_invalid_dates in your MySQL configuration (see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_allow_invalid_dates)
write java code to catch the date exceptions and deal with the bad data
write SQL to substitute a default date for invalid date, as suggested by John Woo.
The problem with 3 is that there are other invalid dates (e.g. '2012-02-31') that might throw exceptions also. Good luck.
if you are retrieving rows from the database, format the dates in your select statement,
SELECT if(colDate = '0000-00-00', curdate(), colDate), ....
just replace CURDATE() to your desired default date. The reason why the exception arises is because 0000-00-00 is not a valid date.

'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

Categories