我面临着必须查看具有数百万条记录的数据库的任务,一组约1500条记录的代码具有相应的记录,其中一些记录存在于数据库中。例如,我在csv文件中有1500个ID。我想知道数据库中存在哪些ID,因此是正确的,哪些不存在。
如果没有“...... WHERE id IN (1, 2, 3, ..., 1500);
”,有没有更好的方法呢?
有问题的DB /语言是ORACLE PL / SQL。
提前感谢您的帮助。
答案 0 :(得分:3)
在CSV文件上构建外部表。这些是非常巧妙的东西,它们允许我们在SQL中查询OS文件的内容。 Find out more。
然后发出查询很简单:
select csv.id
, case ( when tgt.id is null then 'invalid' else 'valid') end as valid_id
from your_external_tab csv
left join target_table tgt on (csv.id = tgt.id)
“从性能的角度来看,CSV表并不理想”
表现是一个背景问题。在这种情况下,它取决于CSV中的数据更改的频率以及我们查询它的频率。如果文件每天生成一次,我们只需要在交付后检查它们,那么外部表是最有效的解决方案。但是,如果这个数据集是一个需要经常查询的永久存储库,那么写入堆表的开销显然是合理的。
对我而言,一个由一堆ID组成的CSV文件听起来就像瞬态数据一样 适合外部表的用例。但是OP可能有其他要求,他们没有提到。
这是一种替代方法,不需要创建任何永久数据库对象。因此它不那么优雅,而且可能表现更差。
它使用UTL_FILE实时读取CSV文件,并根据SYSTEM.NUMBER_TBL_TYPE填充一个集合,SYSTEM.NUMBER_TBL_TYPE是一个预定义的集合(NUMBER的嵌套表),应该在Oracle数据库中可用。
declare
ids system.number_tbl_type;
fh utl_file.file_handle;
idx pls_integer := 0;
n pls_integer;
begin
fh := utl_file.fopen('your_data_directory', 'your_data.csv', 'r');
begin
utl_file.get_line(fh, n);
loop
idx := idx + 1;
ids.extend();
ids(idx) := n;
utl_file.get_line(fh, n);
end loop;
exception
when no_data_found then
if utl_file.is_open(fh) then
utl_file.fclose(fh);
end if;
when others then
raise;
end;
for id_recs in in ( select csv.column_value
, case ( when tgt.id is null then 'invalid' else 'valid') end as valid_id
from (select * from table(ids)) csv
left join target_table tgt on (csv.column_value = tgt.id)
) loop
dbms_output.put_line '(ID '||id_recs.column_value || ' is '||id_recs.valid_id);
end loop;
end;
注意:我没有测试过这段代码。原则是合理的,但细节可能需要调试;)