首页 > 解决方案 > 如何通过 sql loader 设置要加载到表列中的固定长度

问题描述

因此,我想使用我的 shell 脚本通过 sql loader 加载电话号码,因为当我尝试加载包含 9 位数字的数据文件时,脚本也会加载 9 位数字行。我只希望加载 10 位数的行。问题是我希望将 sql 加载器设置为仅接受正好 10 位数字的行。

标签: oracleshellunixaixsql-loader

解决方案


据我所知,你不能;SQL*Loader 无法做到这一点。WHEN子句会非常好,只要它接受像length. 但是,事实并非如此。


我能想到的最简单的选择是全部加载它们,然后删除不需要的行。例如:

表说明:

SQL> desc test
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------
 TEL                                                VARCHAR2(10)

SQL> select * From test;

no rows selected

控制文件:

load data 
infile *
replace
into table test
( 
tel char(10)
)

begindata
1234567890
986532554
3216549878
21212

运行:

SQL> $sqlldr scott/tiger control=test19.ctl log=test19.log

SQL*Loader: Release 11.2.0.2.0 - Production on Pon Svi 4 21:46:17 2020

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Commit point reached - logical record count 4

SQL> select * From test;

TEL
----------
1234567890
986532554
3216549878
21212

删除你不想要的:

SQL> delete from test where length(tel) < 10;

2 rows deleted.

SQL> select * From test;

TEL
----------
1234567890
3216549878

SQL>

另一个会默默跳过不需要的值的选项是数据库触发器。为了做到这一点,创建一个基于表的视图和一个代替触发器:

SQL> truncate table test;

Table truncated.

SQL> create or replace view v_test as select * From test;

View created.

SQL> create or replace trigger trg_bivt
  2    instead of insert on v_test
  3    for each row
  4  begin
  5    if length(:new.tel) < 10 then
  6       null;
  7    else
  8       insert into test (tel) values (:new.tel);
  9    end if;
 10  end;
 11  /

Trigger created.

让我们尝试一下:

SQL> $sqlldr scott/tiger control=test19.ctl log=test19.log

SQL*Loader: Release 11.2.0.2.0 - Production on Pon Svi 4 21:52:59 2020

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

Commit point reached - logical record count 4

SQL> select * From test;

TEL
----------
1234567890
3216549878

SQL>

这个选项很好,但是当您加载大量数据时性能会受到影响。


另一种选择是外部表。它的好处是可以将源文件视为普通的 Oracle 表——您可以直接针对它编写查询。为了使用它,创建一个目录并向将使用它的用户授予权限:

SQL> show user
USER is "SYS"
SQL> create directory ext_dir as 'c:\temp';

Directory created.

SQL> grant read, write on directory ext_dir to scott;

Grant succeeded.

SQL>

创建外部表:

SQL> show user
USER is "SCOTT"
SQL> create table test_ext
  2    (tel varchar2(10))
  3  organization external
  4    (type oracle_loader
  5     default directory ext_dir
  6     access parameters (records delimited by newline
  7                        fields terminated by ','
  8                          (tel char(10))
  9                       )
 10     location ('test.txt')
 11    )
 12    reject limit unlimited;

Table created.

SQL>

Test.txt 内容:

1234567890
986532554
3216549878
21212

它有效吗?

SQL> select * From test_ext;

TEL
----------
1234567890
986532554
3216549878
21212

SQL>

现在,只插入您想要接受的行:

SQL> truncate table test;

Table truncated.

SQL> insert into test (tel)
  2  select tel
  3    from test_ext
  4    where length(tel) = 10;

2 rows created.

SQL> select * from test;

TEL
----------
1234567890
3216549878

SQL>

此选项的唯一缺点是您必须有权访问(一般而言)位于数据库服务器上的目录,因此您必须与您的 DBA 交谈。


如您所见,有很多选择,但没有一个完全符合您的要求。


推荐阅读