Oracle 如何使用sql loader加载不一致的CSV文件?

Oracle 如何使用sql loader加载不一致的CSV文件?,oracle,sql-loader,Oracle,Sql Loader,我有下面的示例csv文件 ,,,Test File, ,todays Date:,01/10/2018,Generation date,10/01/2019 11:20:58 Header 1,Header 2,Header 3,Header 4,Header 5 ,My account no,100102GFC,, A,B,C,D,E A,B,C,D,E A,B,C,D,E ,,测试文件, ,今天日期:,2018年10月1日,发电日期,2019年1月10日11:20:58 收割台1、收割台2、

我有下面的示例csv文件

,,,Test File, ,todays Date:,01/10/2018,Generation date,10/01/2019 11:20:58 Header 1,Header 2,Header 3,Header 4,Header 5 ,My account no,100102GFC,, A,B,C,D,E A,B,C,D,E A,B,C,D,E ,,测试文件, ,今天日期:,2018年10月1日,发电日期,2019年1月10日11:20:58 收割台1、收割台2、收割台3、收割台4、收割台5 ,我的账号为100102GFC,, A、 B,C,D,E A、 B,C,D,E A、 B,C,D,E 下面是我的表格结构

Todays Date,My account,Header 1,Header 2,Header 3,Header 4,Header 5 01/10/2018,100102GFC,A,B,C,D,E 01/10/2018,100102GFC,A,B,C,D,E 01/10/2018,100102GFC,A,B,C,D,E 今天日期,我的帐户,标题1,标题2,标题3,标题4,标题5 01/10/2018100102GFC,A,B,C,D,E 01/10/2018100102GFC,A,B,C,D,E 01/10/2018100102GFC,A,B,C,D,E 我在从文件的第二行获取今天的日期和从文件的第四行获取账号时遇到问题。前四行是一致的。我的实际数据从第五行开始


是否可以从第2行和第4行获取特定值,并从第5行开始将其与其他值一起加载?如何在控制文件中处理此问题?

您可以有条件地将记录加载到不同的表中。因此,您可以通过以下方式实现此效果:

  • 创建三个临时表:加载日期、帐户日期和加载数据
  • 将记录加载到适当的表中
  • 交叉连接结果以获得输出
例如,创建以下临时表:

create table t (
  c1 varchar2(1),
  c2 varchar2(1),
  c3 varchar2(1),
  c4 varchar2(1),
  c5 varchar2(1)
);

create table dt (
  load_date date
);

create table act (
  acct# varchar2(20)
);
然后使用以下控制文件说明何时将哪些记录加载到每个表中:

LOAD DATA
infile *
TRUNCATE 
INTO TABLE dt WHEN (2:13) = 'todays Date:'
FIELDS TERMINATED BY ","
DATE FORMAT "DD/MM/YYYY"
TRAILING NULLCOLS
(
c1 filler, c2 filler, load_date date, c4 filler, c5 filler
)
INTO TABLE act WHEN (2:14) = 'My account no'
FIELDS TERMINATED BY ","
TRAILING NULLCOLS
(
c1 filler position(1:1), c2 filler, acct#, c4 filler, c5 filler
)
INTO TABLE t WHEN (1:1) <> ','
FIELDS TERMINATED BY ","
TRAILING NULLCOLS
(
c1 position(1), c2, c3, c4, c5 
)
BEGINDATA
,,,Test File,
,todays Date:,01/10/2018,Generation date,10/01/2019 11:20:58
Header 1,Header 2,Header 3,Header 4,Header 5
,My account no,100102GFC,,
A,B,C,D,E
A,B,C,D,E
A,B,C,D,E
您所要做的就是将这些交叉连接在一起,以获得您想要的结果:

select * from dt
cross  join act
cross  join t;

LOAD_DATE           ACCT#       C1   C2   C3   C4   C5   
01-OCT-2018 00:00   100102GFC   A    B    C    D    E    
01-OCT-2018 00:00   100102GFC   A    B    C    D    E    
01-OCT-2018 00:00   100102GFC   A    B    C    D    E 

这有点乱。如果您能够将文件传输到数据库服务器,那么使用外部表将更容易。

处理加载的常见方法也是将所有行加载到临时表中。例如,您可以创建一个包含5个varchar2列(数据中最大的列数)的临时表。截断所有行并按原样加载到暂存表中

然后创建一个PL/SQL脚本以运行下一步,该脚本将数据从临时表加载到生产表中,并在导入过程中执行验证和转换。将其设置为存储过程

declare
  save_date date;
  save_acct_nbr varchar2(10);
begin

    execute immediate 'truncate table x_test';

    -- Save the file date
    select to_date(col3, 'MM/DD/YYYY')
    into save_date
    from X_TEST_STG
    where col2 = 'todays Date:';

    -- Save the account number
    select col3
    into save_acct_nbr
    from X_TEST_STG
    where col2 = 'My account no';

    insert into x_test
    (select save_date, save_acct_nbr, col1, col2, col3, col4, col5
     from X_TEST_STG
     where col1 is not null
     and col1 != 'Header 1');

    commit;
end;
巴达宾,巴达邦


如果这是SQL Server,我只需将每一行加载到单个varchar字段中,然后使用T-SQL将其拆分。不确定您是否可以在Oracle中执行此操作。如果您知道只有第二行和第四行被打断,请从文件中编辑这些行,只导入其余的行并手动添加麻烦制造者。SQL Loader允许您跳过前4行-这就是您要问的吗?@a_horse_with_no_name no,我需要从第2行和第4行取值,然后只跳过前4行。我需要附加日期和帐号以及其他数据。您需要编写一个shell脚本(或批处理文件),首先提取这些值,然后调整控制文件,然后跳过第一行。如果
todays-date
始终是“todays”日期,那么您可以简单地使用
sysdate
作为该列的默认值。嘿!!谢谢你的解决方案。我已经考虑过了,但是我们需要在所有3个表中都有一个唯一的键,可以连接。我们需要每天存储数据。因此,对于单个加载是可以的,但是对于下一个加载,它会给人错误的印象,是否可能在所有表中都有一个唯一的标识符?如果是,怎么做?我不知道你的意思。其思想是将数据加载到三个临时表中。然后把它放到真正的桌子上。。我现在明白了..下一次加载时,3个表将始终被截断。。主表将包含实际数据。。谢谢:)
declare
  save_date date;
  save_acct_nbr varchar2(10);
begin

    execute immediate 'truncate table x_test';

    -- Save the file date
    select to_date(col3, 'MM/DD/YYYY')
    into save_date
    from X_TEST_STG
    where col2 = 'todays Date:';

    -- Save the account number
    select col3
    into save_acct_nbr
    from X_TEST_STG
    where col2 = 'My account no';

    insert into x_test
    (select save_date, save_acct_nbr, col1, col2, col3, col4, col5
     from X_TEST_STG
     where col1 is not null
     and col1 != 'Header 1');

    commit;
end;