【问题标题】:Import hour, minute, second from csv to timestamp column in external table从csv导入小时、分钟、秒到外部表中的时间戳列
【发布时间】:2020-02-07 05:37:13
【问题描述】:

我正在尝试将 csv 数据文件转换为 oracle 数据库表。为此,我将使用here 所述的外部表。

我的 csv 中的时间戳分为一侧的日期 (yyyy-mm-dd) 和另一侧的时间 (hh24:mm:ss) .

我的表有 3 列:

create table backup_ext
(
    "user"    NVARCHAR2(20),
    "date"    DATE,
    "hour"    TIMESTAMP
)

这是 csv 的样子:

john,2018-05-28,10:17:57

我需要将这三个值放在表中的三个单独的列中。

我遇到的问题是用户和日期以预期的格式显示,但小时中有日期和时间,如下所示:

user        |date        |hour
----------------------------------------
john         28-MAY-18    01-OCT-19 10.17.57.000000000

我想要的是这样的:

user        |date        |hour
----------------------------------------
john         28-MAY-18    10.17.57

其他特殊性

  • 我想尽可能避免更改列类型,因为它在程序的许多其他区域都按原样使用,我不想破坏任何东西
  • 表是这样创建的,用于 MSSQL,我的任务是调整它以与 Oracle 一起使用,这可以解释列类型的选择
  • 之后我可能会运行第二段 sql 代码来格式化列,尽管我不知道具体该怎么做
  • 我只能使用 sql 语句,因为这是通过 C++ 代码创建语句并使用所述语句查询数据库来完成的

任何帮助将不胜感激

完整代码:

create table backup_ext
(
    "user"    NVARCHAR2(20),
    "date"    DATE,
    "hour"    TIMESTAMP
)
organization external
(
     type oracle_loader
     default directory csvdir
     access parameters 
     (
         records delimited by newline
         skip 1
         fields terminated by ';' lrtrim
         missing field values are null
         (
             "user",
             "date" date 'yyyy-mm-dd',
             "hour" Char Date_Format Timestamp Mask 'hh24:mi:ss',
         )
     )
     location ('backup.csv')
)
reject limit unlimited;

【问题讨论】:

  • 我不确定我是否理解你得到的和你想要的之间的区别。 timestamp 列总是有一天和一个精确到亚秒级的时间。查询时间戳的客户端应用程序通常必须将其转换为字符串,以便显示对人类有意义的内容。您当然可以选择让您的客户端应用程序将时间戳转换为仅显示时间戳的某些组件的字符串,即select to_char("hour", 'HH24:MI:SS') from backup_ext
  • 在 SQL*Plus 中,您可以通过设置 nls_timestamp_format,即 alter session set nls_timestamp_format = "HH24.MI.SS" 来控制会话的默认值,以将时间戳转换为字符串以供显示。当然,这只适用于您的会话,如果我从不同的会话中查询数据,我可能会选择获取相同时间戳数据的完全不同的字符串表示形式。

标签: oracle csv sqlplus datetime-format external-tables


【解决方案1】:

您说您不想更改任何内容,但您已经将其从 SQL Server 迁移到 Oracle...现在是修复它的时候了,否则您将在整个时间内讨厌生活支持这个应用程序/数据库向前发展。

您的数据只需要两列

DROP TABLE BACKUP_EXT;

CREATE TABLE BACKUP_EXT (
       USERNAME    VARCHAR2(20),
       OCCURENCE   DATE
);

INSERT INTO BACKUP_EXT VALUES (
       'john',
       TO_DATE('28-MAY-18 10.17.57', 'DD-MON-RR HH.MI.SS')
);

COMMIT;

SELECT USERNAME "user",
       TO_CHAR(OCCURENCE, 'DD-MON-RR') "date",
       TO_CHAR(OCCURENCE, 'HH.MI.SS') "hour"
  FROM BACKUP_EXT;

执行那个......我们回来......

Table BACKUP_EXT dropped.


Table BACKUP_EXT created.


1 row inserted.


Commit complete.

user   date        hour       
john    28-MAY-18    10.17.57    

使用正确的数据类型 -> DATE。 DATE 包含一个时间点,因此它包括一个时间部分,而不仅仅是月、日、年。

不要使用 NVARCHAR2 - 大多数现代 oracle 数据库已经使用基于 Unicode 的字符集,因此没有必要,尤其是对于您提供的测试数据。

不要在表名或列名中使用 DATE 或 USER 之类的保留字 - 这会导致比用引号强制解决的问题要多得多。

【讨论】:

  • 尽管我很喜欢现在解决问题的想法,但还有许多其他应用程序依赖于查询小时列,因为它是使用 MSSQL 构建的,我认为我们负担不起要么更改所有内容,要么为所有内容创建特定的“Oracle”案例
  • 然后创建一个拆分时间部分的视图,就像我在上面显示的查询中一样,将其命名为您的 SQL 表的名称,一切都会好起来的。
  • 根据您当前的数据模型,查看该表的人可以从两个不同的列中选择时间部分,我猜它们并不总是相同的......所以有人将要编写代码并获取错误的数据。最好拥有一个事实来源 - 然后从该单一来源构建尽可能多的视图。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 2021-04-02
  • 1970-01-01
  • 2017-06-11
  • 2013-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多