通过JDBC PreparedStatement

时间:2018-03-11 16:42:49

标签: java oracle date jdbc

对抗Oracle数据库。它有一个DATE类型列,并且通过JDBC PreparedStatement发出的select(这里简化为易读)语句如下所示:

select  DATE1 from TYPE_TABLE  where TYPE_TABLE.DATE1 =  ?

运行时的问号参数值为2018-01-31 12:50:30.0 PST。我们通过PreparedStatement类的setTimeStamp API设置参数。我们在执行上述选择查询时看到的错误如下:

java.sql.SQLDataException: ORA-01830: date format picture ends before 
converting entire input string 

我搜索过SE网络的SO和其他姐妹站点,我发现的所有引用都与将日期插入数据库有关,而没有使用正确的格式掩码。但我还没有发现任何与select语句有关的内容。

这可能是什么问题和解决方案?

P.S:DATE1列的类型确实是Oracle DB中的DATE类型。

编辑:如果此处存在NLS_DATE_FORMAT参数问题,那么该问题的日期值应采用何种格式(即2018-01-31 12:50:30.0 PST)?

4 个答案:

答案 0 :(得分:2)

TL;博士

您尚未提供任何代码,因此我们无法破译确切的问题。但请继续阅读以获得一些指导。

错误的数据类型:您的问题可能是由于在UTC(java.sql.Timestamp)中传递一个时刻以便与缺少任何区域的DATE类型的列进行比较偏移量(不是UTC,不是任何区域/偏移量)。

使用JDBC 4.2或更高版本。传递 java.time 对象而不是字符串。

myPreparedStatement.setObject( 
    … , 
    LocalDateTime.of( 
        LocalDate.of( 2018 , Month.January , 23 ) , 
        LocalTime.of( 12 , 34 , 56 ) 
    ) 
)

Oracle DATE类型

正如其他人所说,Oracle 11g等中的DATE类型只是一个日期值(它有一个时间),并且不是在标准SQL中定义。它是一个缺少区域/偏移的日期时间,可能类似于SQL标准TIMESTAMP WITHOUT TIME ZONE类型。这意味着这样的值特定时刻,只是对大约26-27小时范围内潜在时刻的粗略概念。

对于缺少任何时区概念或从UTC偏移的日期时间值,在Java中使用的类是LocalDateTime

LocalDate ld = LocalDate.of( 2018 , Month.January , 23 ) ;
LocalTime lt = LocalTime.of( 12 , 34 , 56 ) ;
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;
  

ldt.toString():2018-01-23T12:34:56

提示:请记住,这不是一个时刻。如果您想要片刻,则需要将此LocalDateTime置于时区(或从UTC偏移)的上下文中。通过应用ZoneId来获取ZonedDateTime对象来实现此目的。搜索Stack Overflow以获取更多信息和示例。

  

我们通过PreparedStatement类的setTimeStamp API设置参数。

java.sql.Timestamp暂时是时间轴上的特定点,以UTC为单位。标准SQL中的等效类型是TIMESTAMP WITH TIME ZONE。此类型适用于您的Oracle DATE列 - 如上所述,Oracle DATE 片刻。

此外,您不应再使用java.sql.Timestamp,因为它现在是遗留的,取而代之的是java.time.Instant类。

将Oracle DATE值检索到Java中:

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

智能对象,而不是哑字符串

  

如果此处存在NLS_DATE_FORMAT参数问题,那么应该使用什么格式来处理相关日期值(即2018-01-31 12:50:30.0 PST)?

根本不使用字符串。使用符合JDBC 4.2或更高版本的JDBC驱动程序与Oracle数据库交换 java.time 对象。

从JDBC 4.2及更高版本开始,您可以直接交换 java.time 对象。不需要字符串。使用日期时间值时,不再需要 java.sql 类。

避免使用遗留日期时间类,例如DateCalendarTimestamp。这些都非常令人困惑,设计糟糕,而且全面麻烦。仅使用 java.time 类。

对于SQL,例如:

SELECT some_date FROM some_table  where some_date =  ? ;

...通过调用LocalDateTimePreparedStatement占位符传递给setObject

myPreparedStatement.setObject( … , ldt ) ;

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:1)

Oracle使用7个字节存储日期。世纪,年,月,日,小时,分钟和秒各一个字节。因此,必须使用相应的格式字符串传递任何字符串,以指定该字符串的每个组件将如何解析为7字节日期。

select DATE1 
  from TYPE_TABLE  
 where TYPE_TABLE.DATE1 = to_date('2018-01-31 12:50:30', 'yyyy-mm-dd hh24:mi:ss');

如果未指定格式,Oracle将使用NLS_DATE_FORMAT参数中提供的默认格式。如果默认格式与使用的字符串不匹配,则会出现此错误:

ORA-01830: date format picture ends before  converting entire input string

答案 2 :(得分:1)

Oracle不符合SQL:数据类型DATE包含小时,分钟和秒。

文档说:

  

此数据类型包含日期时间字段YEAR,MONTH,DAY,HOUR,MINUTE和SECOND。它没有小数秒或时区。

只有在您进行分秒和/或想要存储时区信息时才需要时间戳。

您可以尝试使用setDate()吗?

答案 3 :(得分:0)

一个公平的猜测是你的JDBC驱动程序会将Oracle Data类型转换为java.sql.TimeStamp或java.sql.Date类型(并注意java.util.Date和java.sql.Date之间存在差异) ,就精度而言,例如)。例如,在java.sql.Timestamp类型的情况下,请尝试指定:

ret.value = java.sql.Timestamp(java.util.Date().getTime()); copy to clipboard
and see if this helps. Then you will be able to use:
ret.value = java.sql.Timestamp(system.parseDate(work.getString("yourDate"), 
    "yyyyMMddHHmmssz").getTime());