对抗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
)?
答案 0 :(得分:2)
您尚未提供任何代码,因此我们无法破译确切的问题。但请继续阅读以获得一些指导。
错误的数据类型:您的问题可能是由于在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 )
)
)
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 类。
避免使用遗留日期时间类,例如Date
,Calendar
和Timestamp
。这些都非常令人困惑,设计糟糕,而且全面麻烦。仅使用 java.time 类。
对于SQL,例如:
SELECT some_date FROM some_table where some_date = ? ;
...通过调用LocalDateTime
将PreparedStatement
占位符传递给setObject
。
myPreparedStatement.setObject( … , ldt ) ;
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance 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的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 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());