在ORACLE数据库运维和开发工作中,将TXT文本文件中的数据迁移进库是常见需求。TXT文件通常由其他系统导出,格式可能是逗号分隔、制表符分隔或固定长度,字符集也可能是GBK或UTF-8。如果直接手工录入显然不现实,必须借助ORACLE自身或系统级工具来完成批量装载。不同的数据规模和格式复杂度,对应不同的解决思路,理解这些思路能帮助你避开乱码、字段错位等典型坑。

一、使用SQLLoader进行高效装载
SQLLoader是ORACLE官方提供的命令行数据加载工具,专门用于将平面文件(如TXT)导入数据库表。它的核心是一个控制文件(control file),在控制文件中你需要声明数据文件路径、目标表名、列分隔方式以及每个字段的类型转换规则。这种方式适合十万行甚至上亿行的大批量数据,因为它绕过了SQL层逐行插入的开销,直接以块方式写入。
下面给出一个典型的控制文件示例,假设TXT为逗号分隔,第一行是表头需要跳过:
LOAD DATA INFILE '/home/oracle/data/user.txt' BADFILE '/home/oracle/data/user.bad' DISCARDFILE '/home/oracle/data/user.dsc' APPEND INTO TABLE user_info FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' TRAILING NULLCOLS ( id INTEGER EXTERNAL, name CHAR(50), birth DATE 'YYYY-MM-DD', salary FLOAT EXTERNAL )
在命令行执行 sqlldr userid=scott/tiger control=load.ctl 即可启动。SQLLoader的优势在于稳定且可断点续做,错误行会写入BAD文件便于排查。缺点是控制文件需要事先写好,对复杂格式(如嵌套引号)调试成本略高。另外要注意客户端与服务端字符集一致,否则中文容易变乱码。
二、通过外部表实现灵活查询导入
外部表(External Table)是ORACLE将操作系统文件以表的形式暴露给数据库的机制。它并不真正把数据搬进库,而是允许你用SELECT语句直接查TXT内容,再通过INSERT INTO ... SELECT把数据写入正式表。这种思路在需要先做清洗、过滤再入库时非常方便。
创建外部表依赖于目录对象(DIRECTORY)和ORACLE_LOADER驱动。示例如下:
CREATE DIRECTORY ext_dir AS '/home/oracle/data';
CREATE TABLE ext_user
(
id NUMBER,
name VARCHAR2(50),
birth DATE,
salary NUMBER
)
ORGANIZATION EXTERNAL
(
TYPE ORACLE_LOADER
DEFAULT DIRECTORY ext_dir
ACCESS PARAMETERS
(
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY ','
MISSING FIELD VALUES ARE NULL
)
LOCATION ('user.txt')
);
INSERT INTO user_info
SELECT id, name, birth, salary FROM ext_user WHERE salary > 3000;
外部表的好处是可以用SQL做转换,比如只导薪资大于3000的记录。但它要求数据库进程能读取该文件,权限配置比SQLLoader更严格。性能上对于超大数据量略逊于直接SQLLoader装载,但开发调试更直观。
三、利用PL/SQL与UTL_FILE读取
当数据量很小,且环境不允许使用客户端工具时,可以写PL/SQL存储过程,借助UTL_FILE包在数据库服务端按行读取TXT,再拼成INSERT语句。这种方式最灵活,但最容易出错,特别是换行符在Windows与Linux下不同(CR/LF差异),以及目录权限未授权会导致程序直接报错。
简单示例如下,注意要先创建目录并赋权:
DECLARE
f UTL_FILE.FILE_TYPE;
line VARCHAR2(4000);
v_id NUMBER;
v_name VARCHAR2(50);
BEGIN
f := UTL_FILE.FOPEN('EXT_DIR', 'user.txt', 'R');
LOOP
UTL_FILE.GET_LINE(f, line);
EXIT WHEN line IS NULL;
v_id := TO_NUMBER(SUBSTR(line, 1, INSTR(line, ',') - 1));
v_name := SUBSTR(line, INSTR(line, ',') + 1);
INSERT INTO user_info(id, name) VALUES(v_id, v_name);
END LOOP;
UTL_FILE.FCLOSE(f);
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
UTL_FILE.FCLOSE(f);
COMMIT;
END;
UTL_FILE只能读数据库服务器本地文件,如果TXT在远程机器需先传上去。且每行解析要自己写逻辑,字段多时代码冗长。新手常误以为它能读客户端文件,这是概念错误。一般不推荐作为常规导入方案,仅适合特殊运维场景。
四、字符集与格式避坑要点
无论选哪种思路,TXT的字符集必须和ORACLE数据库或会话字符集兼容。例如库为AL32UTF8,而TXT是GBK,直接导会出现乱码。可在控制文件或外部表参数中指定字符集,如 CHARACTERSET ZHS16GBK。另外分隔符要确认文件真实使用是逗号、制表符还是竖线,可用hexdump看二进制避免肉眼误判。
对于带引号的字段,如 "张三","25",要配置 OPTIONALLY ENCLOSED BY '"' 以免引号进库。日期格式也必须显式声明,ORACLE不会自动猜。做好这些前置检查,导入成功率能从一半提升到接近百分之百。
五、方案选择建议
综合来看,大批量、固定格式首选SQLLoader;需要SQL级清洗选外部表;极小量且受限环境才考虑UTL_FILE。理清文件格式、字符集与部署位置,是ORACLE导入TXT数据的三大前提。实际工作中先把样本数据用上述一种思路试跑,观察BAD文件或错误日志,再调整参数批量执行,可显著降低返工成本。