2

Hello everybody,

I am newbie in java. I tried to create such a data pipe line that copy tables from 1 source to different servers & databases. It work fine with String and Number, but I stuck in Date datatype. I got Exception in thread "main" java.sql.SQLException: ORA-01843: not a valid month.

I have no idea how to change the date format in java or work with date data type.

Here the detail : Oracle 10g (Svr1) & 11g (Svr2), java 8 with ojdbc14.jar

The table's DB

Table = LAB
field = ID(INT), LAB_DESC(VARCHAR2, 50), LAB_DATE(DATE)

The Java Code

//========= Bismillah Arrahman Arrahiem =============//
//============== DARI SINI ========================================//
//    **    **  **  **
//  ****    **  **  **     ****        ** ** **     ** 
//  ****    **  **  **     *  *        ** ** **     **
//     **********   **   ****************************
//                                             *
//
//========================= LAB =============================//
package simpledtpipeline;
import java.sql.*;
public class SimpleDTpipeline {

     public static void main(String[] args) 
       //========= Bismillah =============//
        throws SQLException, ClassNotFoundException, Exception {
 // Load the JDBC driver
 Class.forName("oracle.jdbc.driver.OracleDriver");
 System.out.println("Driver loaded");
//======================================================// 
 // Connect to a database
Connection connectionServer1 = DriverManager.getConnection
("jdbc:oracle:thin:@192.168.7.1:1521:dbone", "user", "pass123");
 System.out.println("Database 192.168.7.1 connected");
//======================================================//
Connection connectionServer2 = DriverManager.getConnection
("jdbc:oracle:thin:@192.168.7.2:1521:dbtwo", "user2", "pass789");
System.out.println("Database 192.168.7.2 connected");
//
//========================= LAB =============================//
Statement SelectLAB = connectionServer1.createStatement();
// Execute a statement
 ResultSet FetchLAB = SelectLAB.executeQuery
("SELECT ID, LAB_DESC, LAB_DATE from LAB ");
//*****************************************************************//
PreparedStatement InsertLAB = connectionServer2.prepareStatement("INSERT INTO LAB "
        + "(ID, LAB_DESC, LAB_DATE) VALUES (?,?, TO_DATE(?,'MM/DD/YYYY')");
while (FetchLAB.next()){
    InsertLAB.setInt(1,FetchLAB.getInt("ID")); 
    InsertLAB.setString(2,FetchLAB.getString("LAB_DESC")); 
    InsertLAB.setString(3,FetchLAB.getString("LAB_DATE")); 
    InsertLAB.execute(); 
}
//======================================================//
//
// Close the connection //
 connectionServer1.close();
 connectionServer2.close();
}
       
    }
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • Does this answer your question? [Insert & fetch java.time.LocalDate objects to/from an SQL database such as H2](https://stackoverflow.com/questions/43039614/insert-fetch-java-time-localdate-objects-to-from-an-sql-database-such-as-h2) – Ole V.V. Feb 24 '21 at 06:36

1 Answers1

2

tl;dr

myPreparedStatement
.setObject(                                           // Use `setObject` for java.time types.
    3 ,                                               // Third placeholder in the Question's example text.
    LocalDate                                         // Represent a date-only value, without time-of-day and without time zone.
    .parse(
        "01/23/2020" , 
        DateTimeFormatter.ofPattern( "MM/dd/uuuu" )   // Specify formatting codes for your particular text input’s format. Case-sensitive.
    )
)

Formatting codes

I am guessing that the specific problem in your code is incorrect formatting codes: 'MM/DD/YYYY'. I do not know Oracle Database codes, but I would guess they are case-sensitive, as seen in other such tooling. If so, you may be using the wrong case. Or your formatting codes do not match the actual text of your inputs.

Either way, the issue is moot. You should be passing Java objects for your date-time values instead of plain text.

Use date-time objects in Java

You date-time objects on the Java side, rather than mere strings.

Use only the java.time classes in Java, never the legacy classes such as Date, Calendar, and SimpleDateFormat.

JDBC 4.2 requires a JDBC driver to support a subset of the java.time types.

Table of date-time types in Java (both legacy and modern) and in standard SQL

But unfortunately and mysteriously, the spec does not provide type-specific set… methods for the java.time types. Instead, we use setObject on the prepared statement, and getObject on the result set.

LocalDate localDate = LocalDate.of( 2022 , Month.JANUARY , 23 ) ;
myPreparedStatement.setObject( … , localDate ) ;

And retrieval.

LocalDate localDate = myResultSet.getObject( … , LocalDate.class ) ;

If your inputs are text in the format of month/day/year numbers, parse into LocalDate objects. Trap for DateTimeParseException in case of faulty inputs.

String input = "01/23/2022" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate localDate = LocalDate.parse( input , format ) ;

Using localized formats for such text in data-exchange is a poor practice. I suggest you educate the publisher of that textual data about the ISO 8601 standard format for dates: YYYY-MM-DD. So January 23 of 2022 would be 2022-01-23.

Unrelated tips

Calling Class.forName to load a JDBC driver is old-school. No longer necessary for modern Java.

Generally advised to use a DataSource implementation for your particular database rather to hold info to make database connections. Your JDBC driver should provide such an implementation.

The JDBC resources such as Connection and ResultSet implement the AutoCloseable interface. This means we can use try-with-resources syntax to automatically close these resources while simplifying our code.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.

Where to obtain the java.time classes?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • I had trying ``` InsertLAB.setObject( // Use `setObject` for java.time types. 3 , // Third placeholder in the Question's example text. LocalDate // Represent a date-only value, without time-of-day and without time zone. .parse( FetchLAB.getString("LAB_DATE") , DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) // Specify formatting codes for your particular text input’s format. Case-sensitive. ) ); ``` – diki-drezto Feb 24 '21 at 02:09
  • and got this message Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-02-24 00:00:00.0' could not be parsed at index 2 – diki-drezto Feb 24 '21 at 02:10
  • at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) at java.time.LocalDate.parse(LocalDate.java:400) at simpledtpipeline.SimpleDTpipeline.main(SimpleDTpipeline.java:42) C:\Users\Handiki-Shinta\AppData\Local\NetBeans\Cache\12.2\executor-snippets\run.xml:111: The following error occurred while executing this line: C:\Users\Handiki-Shinta\AppData\Local\NetBeans\Cache\12.2\executor-snippets\run.xml:94: Java returned: 1 BUILD FAILED (total time: 0 seconds) – diki-drezto Feb 24 '21 at 02:11
  • 2
    Very good answer. It may worth mentioning that with `setObject()` we need the SQL to be `INSERT INTO LAB (ID, LAB_DESC, LAB_DATE) VALUES (?,?, ?);` with no call to `TO_DATE()`. – Ole V.V. Feb 24 '21 at 06:39
  • 1
    thank a lot for your reply & knowledge share @Basil Bourque – diki-drezto Feb 24 '21 at 07:07