找回密码
 立即注册
首页 业界区 业界 高效办公:用SQL*Loader轻松实现Excel数据入库 ...

高效办公:用SQL*Loader轻松实现Excel数据入库

仟仞 2025-11-14 08:40:04
翻看十年前的博客,我曾轻描淡写地记录着使用 SQL*Loader 的“轻松”经历。
没想到,这个我以为毫无难度的工具,在十年后的今天却结结实实地给我上了一课。
当问题出现时,我求助了多位“AI老师”,但它们给出的答案都未能药到病除。几经周折,最终还是得靠自己深入细节、焦头烂额地排查,才找到了症结所在。
回顾整个排查过程,总结经验教训,梳理成本文,方便读者或未来的自己能在有需要时可以直接使用不踩坑,掌握这种能直接将Excel数据“搬”进数据库的办公硬技能。
1.解决Mac导出CSV的兼容性问题

Mac上直接将Excel文件另存为CSV格式,注意选下面这个UTF-8格式的,否则中文会乱码。
1.jpeg

开始以为这样就OK,结果还是存在隐藏特殊字符的问题。
这里提供一个shell脚本 vi clean_csv_for_sqlldr.sh 来二次处理,内容如下:
  1. #!/bin/bash
  2. # 脚本名称:clean_csv_for_sqlldr.sh
  3. # 脚本作用:自动完成 “换行符转换 + 空行清理”
  4. # 使用方法:
  5. # chmod +x clean_csv_for_sqlldr.sh
  6. # ./clean_csv_for_sqlldr.sh your_file_name.csv
  7. #
  8. # 版本:v1.0
  9. # 修改时间:2025年11月12日
  10. # 作者:Alfred
  11. # 检查是否提供了文件名参数
  12. if [ $# -ne 1 ]; then
  13.     echo "用法:$0 <需要处理的CSV文件名>"
  14.     echo "示例:$0 utf8-product_Records.csv"
  15.     exit 1
  16. fi
  17. csv_file="$1"
  18. # 检查文件是否存在
  19. if [ ! -f "$csv_file" ]; then
  20.     echo "错误:文件 '$csv_file' 不存在!"
  21.     exit 1
  22. fi
  23. # 步骤1:将Mac换行符\r转换为Unix换行符\n
  24. tr '\r' '\n' < "$csv_file" > "$csv_file.tmp1"
  25. # 步骤2:删除所有空行(保留有效数据行)
  26. awk 'NF > 0 {print}' "$csv_file.tmp1" > "$csv_file.tmp2"
  27. # 步骤3:替换原文件(保留备份)
  28. mv "$csv_file" "$csv_file.bak"  # 备份原文件(可选,避免误操作)
  29. mv "$csv_file.tmp2" "$csv_file"
  30. # 清理临时文件
  31. rm -f "$csv_file.tmp1" "$csv_file.tmp2"
  32. echo "处理完成!"
  33. echo "原文件已备份为:$csv_file.bak"
  34. echo "处理后的文件:$csv_file"
复制代码
注:也许使用 dos2unix 转换更简单,但笔者可能当时被其他连带问题干扰,以为没效果,后来使用这个脚本成功处理。
2.SQL*Loader控制文件配置详解

起初,时间太久甚至忘了sqlldr的控制文件规则,这里先给出一个模版方便举例说明(注意不是最终版本,若不想看过程,可以直接滑到文章最后看最终版):
vi template.ctl
  1. OPTIONS (SKIP=1)  -- 跳过表头行
  2. LOAD DATA
  3. INFILE '.csv'
  4. TRUNCATE INTO TABLE xxx
  5. FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
  6. TRAILING NULLCOLS
  7. (
  8. ...具体字段名1,字段名2...
  9. )
复制代码
需要注意,已经在Oracle数据库中建好对应空表的情况下,这里控制文件中具体字段名大部分都不需要指定类型,可以直接拷贝CSV文件中的表头即可。
但是,关于时间列字段,通常都需要明确下格式,如果不明确会报错,报错再处理也OK:
类似这样的错误:
  1. Record 49: Rejected - Error on table xxxx, column xxdate.
  2. ORA-01861: literal does not match format string
  3. Help: https://docs.oracle.com/error-help/db/ora-01861/
复制代码
举例:常用的TIMESTAMP和DATE声明格式参考:
  1. 某某时间 TIMESTAMP "YYYY/MM/DD HH24:MI:SS.FF3",
  2. 某某日期 DATE "YYYY/MM/DD",
  3. 某某客户,某某数量,某某地点
复制代码
到这里,一般的CSV文件基本上都能搞定入库。
3.CSV数据预处理与优化技巧

笔者遇到还有报错的情况,本质是因为,某某列的内容有换行。
虽然该列被"包含,但是sqlldr没能解析正确,就是这里折腾了很久。
包括各种问豆包、ChatGPT、Grok等模型,都没有给出正确答案,产生各种幻觉,即使我已经把问题描述的很清楚,也给了最小示例。
最终让他们给我官方文档的链接,看文档才发现应该在控制文件中如此设置:
去掉历史常用的这个写法,改成处理带嵌入换行的CSV:
  1. -- FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' -- 历史写法
  2. FIELDS CSV WITH EMBEDDED  -- 处理带嵌入换行的CSV
复制代码
终于不报这个错误了。
4.应对超长字符的实用解决方案

上面处理完,绝大部分数据都能入库成功了。
但是还发现该列仍有少量数据没导入成功,排查发现是因为字符过长导致。虽然表中该列的定义是CLOB,不过看起来sqlldr还是默认当做字符串处理的。
因为这里数据过长的,实际字符串也没有超过4000的,所以直接指定下即可。
  1. c06 CHAR(4000), -- 显示指定
复制代码
手工声明直接定义CHAR(4000),终于成功导入所有行。
5.总结

其实这里遇到的每个问题都不大,但是混杂在一起时,就容易迷失方向。
笔者最终采用最小化测试用例,逐一排查依次解决的方式,终于成功导入了所有数据。
总结就是:

  • 1.要注意处理文件特殊字符,尤其针对不同平台的换行符。
  • 2.本次经验,给出的控制文件最终示例,vi 4.ctl 内容如下:
  1. OPTIONS (SKIP=1)  -- 跳过表头行
  2. LOAD DATA
  3. INFILE '4-xxx.csv'
  4. TRUNCATE INTO TABLE your_table_name
  5. FIELDS CSV WITH EMBEDDED -- 处理带嵌入换行的CSV效果很好
  6. TRAILING NULLCOLS
  7. (
  8. ID,
  9. start_date TIMESTAMP "YYYY/MM/DD HH24:MI:SS.FF3",  -- 时间TIMESTAMP指定
  10. c03 DATE "YYYY/MM/DD", -- 时间DATE指定
  11. c06 CHAR(4000), -- 超长字符定义
  12. c10,c_level --其他普通列正常无需指定,快速通过CSV文件中的表头复制
  13. )
复制代码

  • 3.导入命令示例,尽可能简化命名,方便排查问题:
  1. $ sqlldr user/password@service_name control=4.ctl log=4.log
复制代码
尽管这只是使用一个Oracle小工具的微末之事,但在各路大模型都无法给出正解的当下,为这样一个具体而微的问题留下清晰的注脚,或许正是技术记录在AI时代新的意义所在。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册