从 Oracle DB 读取时,日期(数据类型)到时间戳(数据类型)的转换不正确

Posted

技术标签:

【中文标题】从 Oracle DB 读取时,日期(数据类型)到时间戳(数据类型)的转换不正确【英文标题】:Incorrect conversion of Date (data type) to TimeStamp (data type) while reading from Oracle DB 【发布时间】:2017-03-06 06:42:37 【问题描述】:

我们正在尝试从 Oracle 表中读取数据,基于“日期”的数据类型被转换为“时间戳”数据类型。

例如:表是 Oracle。

desc hr.employees;

Name Null? Type
-----------------------------------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)
SSN VARCHAR2(55)

以及在 Scala 中的 DataFrame 中读取的架构

|-- EMPLOYEE_ID: decimal(6,0) (nullable = false)    
|-- FIRST_NAME: string (nullable = true)    
|-- LAST_NAME: string (nullable = false)    
|-- EMAIL: string (nullable = false)    
|-- PHONE_NUMBER: string (nullable = true)    
|-- HIRE_DATE: timestamp (nullable = false) (Incorrect data type read here)    
|-- JOB_ID: string (nullable = false)    
|-- SALARY: decimal(8,2) (nullable = true)    
|-- COMMISSION_PCT: decimal(2,2) (nullable = true)    
|-- MANAGER_ID: decimal(6,0) (nullable = true)    
|-- DEPARTMENT_ID: decimal(4,0) (nullable = true)    
|-- SSN: string (nullable = true)

Hire_Date 被错误地读取为时间戳,有没有办法纠正。

正在从 Oracle 动态读取数据,并且应用程序没有预先了解数据类型,并且在读取后无法对其进行转换。

【问题讨论】:

在 Oracle 中,“DATE”类型表示时间戳 Oracle 既有 DATE 又有 TIMESTAMP,如果我理解正确,您是说两者都是同义词? 【参考方案1】:

分析: 根据甲骨文 -

Oracle Database 8i 及更早版本不支持 TIMESTAMP 数据,但 Oracle DATE 数据曾经有一个时间组件作为 SQL 标准的扩展。因此,Oracle 数据库 8i 及更早版本 JDBC 驱动程序版本将 oracle.sql.DATE 映射到 java.sql.Timestamp 保留时间分量。从 Oracle 数据库 9.0.1 开始, 包括 TIMESTAMP 支持,并且 9i JDBC 驱动程序开始映射 oracle.sql.DATE 到 java.sql.Date。此映射不正确,因为它 截断 Oracle DATE 数据的时间部分。为了克服这个 问题,Oracle 数据库 11.1 引入了一个新标志 映射日期到时间戳。此标志的默认值为 true,即 意味着默认情况下驱动程序将正确映射 oracle.sql.DATE 到java.sql.Timestamp,保留时间信息。如果你还 想要不正确但与 10g 兼容的 oracle.sql.DATE 到 java.sql.Date 映射,那么你可以通过设置的值得到它 mapDateToTimestamp 标志为 false。

参考链接是here。

解决方案:

    所以按照 oracle 的指示提供属性 jdbc.oracle.mapDateToTimestamp 为 false -

      Class.forName("oracle.jdbc.driver.OracleDriver")
      var info : java.util.Properties = new java.util.Properties()
      info.put("user", user)
      info.put("password", password)
      info.put("oracle.jdbc.mapDateToTimestamp", "false")
      val jdbcDF = spark.read.jdbc(jdbcURL, tableFullName, info)
    

    添加支持“oracle.jdbc.mapDateToTimestamp”标志的Oracle数据库连接器jar是ojdbc14.jar

希望对您有所帮助!

【讨论】:

以上是关于从 Oracle DB 读取时,日期(数据类型)到时间戳(数据类型)的转换不正确的主要内容,如果未能解决你的问题,请参考以下文章

使用oracle db的日期函数

如何避免两个不同的线程从DB中读取相同的行(Hibernate和Oracle 10g)

Spark SQL - 从 oracle 导入时将 oracle 日期数据类型错误转换为时间戳(java.sql)

需要支持 Oracle 和 DB2 的通用日期函数

从 ASP.NET 中的 Oracle DB 函数读取数据表

db2和oracle字段类型对比