编辑:非常有用的答案 - 谢谢!更多关于那个讨厌的输入文件。字段数是可变的,位置已经改变了几次 - 我当前的脚本通过分析标题行来确定内容(好吧,fastcsv和一个狡猾的转换器这样做)。因此,如果没有多个版本的加载文件,直接上传和后期处理SQL将无法运行,这很糟糕。它也是一个德国的CSV文件:分号分隔(没什么大不了的)和逗号表示的小数(相当大的交易,除非我们加载为VARCHAR和文本处理之后 - 呃)。
以大约7 /秒的速度装载200万行需要花费超过24小时!这可能是日常流程的一个缺点,更不用说用户希望能够以CSV格式提供大约5个小时后才能访问数据!
我考虑过每次网络旅行应用多个插入:相当笨拙的INSERT ALL...
语法会很好,除了目前我正在使用序列为每一行应用唯一的id。它发生了
INSERT ALL
INTO tablea (id,b,c) VALUES (tablea_seq.nextval,1,2)
INTO tablea (id,b,c) VALUES (tablea_seq.nextval,3,4)
INTO tablea (id,b,c) VALUES (tablea_seq.nextval,5,6)
SELECT 1 FROM dual;
(我说这是笨拙的吗?)尝试对所有三行使用相同的id。 Oracle docus似乎证实了这一点。
最新尝试是在一次执行中发送多个INSERT,例如:
INSERT INTO tablea (id,b,c) VALUES (tablea_seq.nextval,1,2);
INSERT INTO tablea (id,b,c) VALUES (tablea_seq.nextval,3,4);
INSERT INTO tablea (id,b,c) VALUES (tablea_seq.nextval,5,6);
我还没有办法说服甲骨文接受这一点。
无论出于何种原因,我更喜欢让我的代码尽可能不受特定于平台的构造的影响:出现这个问题的一个原因是我正在从MySQL迁移到Oracle;由于地理原因,可能有一天会发生另一次移动,我无法确定该平台。因此,使我的数据库库可以使用文本SQL命令来实现合理的扩展是有吸引力的,并且PL / SQL块实现了这一点。现在,如果确实出现了另一个平台,则更改将仅限于在代码中更改适配器:一个单行,很可能。
答案 0 :(得分:10)
如何将csv文件传送到oracle db服务器,使用SQLLoader将csv文件加载到临时表中,然后运行存储过程以在最终表中进行转换和插入?
答案 1 :(得分:4)
您可以使用:
insert into tablea (id,b,c)
( select tablea_seq.nextval,1,2 from dual union all
select tablea_seq.nextval,3,4 from dual union all
select tablea_seq.nextval,3,4 from dual union all
select tablea_seq.nextval,3,4 from dual union all
...
)
当我没记错的时候,这可以工作到最多1024行。
您也可以将其作为PL / SQL批处理指令发送:
BEGIN
INSERT INTO tablea (id,b,c) VALUES (tablea_seq.nextval,1,2);
INSERT INTO tablea (id,b,c) VALUES (tablea_seq.nextval,3,4);
INSERT INTO tablea (id,b,c) VALUES (tablea_seq.nextval,5,6);
...
COMMIT;
END
答案 2 :(得分:2)
我将使用SQL * Loader将原始CSV文件加载到数据库中的专用表而不对其进行规范化,然后针对表中的数据运行代码以将其规范化为各种所需的表。这将最大限度地减少往返次数,并且在Oracle社区中是一种非常传统的方法。
SQL * Loader在初始学习曲线方面可能有点挑战性,但如果你遇到困难,你可以很快再次发布。
http://download.oracle.com/docs/cd/B19306_01/server.102/b14215/part_ldr.htm#i436326
答案 3 :(得分:0)
我有一个快速的建议。我来自MySQL世界,但接受过Oracle培训,我认为这样可行。
在MySQL中,您可以使用单个insert语句插入多个记录。它看起来像这样:
INSERT INTO table_name (column_one, column_two, column_three, column_four)
VALUES
('a', 'one', 'alpha', 'uno'), // Row 1
('b', 'two', 'beta', 'dos'), // Row 2
('c', 'three', 'gamma', 'tres'), // etc.
....
('z', 'twenty-six', 'omega', 'veintiséis');
现在显然你只能一次插入一个表,而你不想做200万条记录,但你可以轻松地一次做10或20或100(如果允许的数据包那么大)。您可能必须手动生成此内容,我不知道您使用的框架(或任何此类内容)是否支持为您制作此类代码。
在MySQL世界中,这种DRAMATICALLY加速了插入。我假设它同时执行所有索引更新,但它也阻止它必须在每个插入上重新解析SQL。
如果将它与预准备语句(因此SQL被缓存并且不必每次都被解析)和事务(以确保在必须跨多个插入时始终处于理智状态)桌子......我想你会做得很好。
NunoG是正确的,您可以将CSV直接加载到Oracle中。您可能最好在输入文件中读取,生成一组标准化的CSV文件(每个表一个),然后一次加载每个文件。
答案 4 :(得分:0)
不是通过网络执行SQL,而是将插入内容写入文本文件,通过网络移动并在那里本地运行。
答案 5 :(得分:0)
SQL * Loader是Oracle提供的实用程序,允许您将平面文件中的数据加载到一个或多个数据库表中。这比使用查询的插入快10-100倍。
http://www.orafaq.com/wiki/SQL*Loader_FAQ
如果SQL * Loader没有删除它,请尝试使用SQL * Loader可读格式格式化文件的小型预处理程序。