我必须每天将大量文件加载到我们的数据库系统中。我的解决方案是使用java过程生成目录文件夹中所有文件的表,并通过外部表加载器循环遍历每个文件。我用这个
遇到了两个挂断Declare
what_to_load VARCHAR2(255);
CURSOR folder_contents
IS
select filename
from database.DIR_LIST
where filename like 'DCOpenOrders_%'
and filename like '%.csv';
BEGIN
DELETE FROM database.DIR_LIST;
database.GET_DIR_LIST( 'directory_path_files_are_in' );
FOR each_record IN folder_contents
LOOP
what_to_load := each_record.filename;
EXECUTE IMMEDIATE 'DROP table database.my_table';
execute immediate 'CREATE table database.my_table
(Region VARCHAR2(10),
District VARCHAR2(10),
Originating_Store VARCHAR2(80),
Order_Date VARCHAR2(30),
Ship_Location VARCHAR2(10),
Orig_Ord_No VARCHAR2(30),
Field_G VARCHAR2(30),
Line_No VARCHAR2(10),
POS_UPC VARCHAR2(30),
Item_Descr VARCHAR2(80),
Ord_Qty VARCHAR2(10),
Line_Status VARCHAR2(30),
Report_Date VARCHAR2(30),
Ship_Type VARCHAR2(30),
ERR_FLAG VARCHAR2(10),
ERR_LOG VARCHAR2(800)
)
ORGANIZATION EXTERNAL
( type oracle_loader
default directory WORK_DIR
access parameters
( records delimited by NEWLINE
skip 1
fields terminated by '',''
optionally enclosed by ''"''
missing FIELD VALUES are NULL)
location ('''||each_record.filename||''')
)
reject limit unlimited';
Execute Immediate 'Grant All on database.my_table to USER';
* merge statement goes here*
End Loop;
commit;
end;
同样,这个想法是,每次运行它将在dir_list表中使用java过程get_dir_list获取新的csv文件列表,然后对于我设置为等于变量的每个文件名,并使用变量外部表加载器加载文件。
我遇到[s]两个[/ s]问题
编辑:好的,对光标行识别进行下面的修改,现在我点到了第二次通过我的光标时出现错误或丢失的情况 - 如果只有这一点,它会经历一个循环就好了动作就是做一个put_line。但是在那里有一个执行立即声明,例如"全部授予"然后,一旦完成一次传递,它会在循环顶部抛出ORA-08103并拒绝继续
3)我知道要求使用alter table命令(https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:37593123416931)。但是,当我尝试它并不接受我的尝试时
execute immediate 'alter table database.my_table location('''||filename||''')';
抛出一个错误(加上我还需要让它在那里做另一个循环,把当前文件的名字放到外部加载器中)
有任何建议或帮助吗?我应该注意到我们在windows上,而不是unix(因为人们在这些地方提供的大多数解决方案都假设后者)而且由于批准限制,我无法抓住另一个程序或模块来完成工作(因为这似乎是另一个常见的解决方案)
谢谢!
答案 0 :(得分:1)
对于您的第一个问题,您的游标循环变量混淆地称为filename
。您直接引用记录,而不是光标中的列。稍微更改名称以使其更清晰:
FOR filenames IN folder_contents
LOOP
what_to_load := filesnames.filename;
其余部分不那么明显,但是你不会感到高兴的是你在一个静态引用它的块的中间放下并重新创建表。您需要使所有引用动态化:
execute immediate 'Grant All on database.my_table ...';
-- grant to who/what? and why?
你的合并也必须是动态的。至少除非你能让alter table工作,但你还没有说出问题所在。实际上,从你发布的内容来看,这是一个相同的游标变量引用问题:
execute immediate 'alter table database.my_table location('''||filenames.filename||''')';
如果您没有在块中删除/创建表,并且静态创建它并且只是更改它,那么您可以使用静态合并 - 只需要更改动态。
更简单的方法可能是创建外部表一次,具有特定的固定名称;循环遍历真实文件列表;并依次将其重命名或复制到固定文件名并执行合并。每次查询外部表时,它都会重新读取文件,因此在后台更改其内容即可。删除/重新创建或甚至改变表格都是不必要的。
您也可以像Ask Tom pst提到的那样,立即将所有文件名提供给外部表,因为它们具有相同的结构,可以使用drop / create或使用alter方法。