如何在 APEX 应用程序的 csv 文件的批量数据插入中使用 forall 语句
Posted
技术标签:
【中文标题】如何在 APEX 应用程序的 csv 文件的批量数据插入中使用 forall 语句【英文标题】:How to use forall statement in bulk data insert of csv file in APEX application 【发布时间】:2017-09-11 13:25:17 【问题描述】:我正在使用下面的代码使用 APEX 5 将数据从 csv 文件上传到 db 表,但性能非常慢,因为 .csv 文件非常大。如何在下面的代码中使用 forall 语句来更快地运行查询?我试图用 forall 替换执行立即语句,但它不起作用。有人可以指导我吗?
DECLARE
v_blob_data BLOB;
v_blob_len NUMBER;
v_position NUMBER;
v_raw_chunk RAW (10000);
v_char CHAR (1);
c_chunk_len NUMBER := 1;
v_line VARCHAR2 (32767) := NULL;
v_data_array wwv_flow_global.vc_arr2;
v_rows NUMBER;
v_sr_no NUMBER := 1;
v_filename VARCHAR2 (2000)
:= APEX_UTIL.get_session_state ('P4_FILE_BROWSE');
v_idx NUMBER;
v_first_line_done BOOLEAN := FALSE;
v_error_cd NUMBER := 0;
TYPE my_rec IS RECORD
(
company_code XXX_COMP_TABLE.company_code%TYPE,
cost_center XXX_COMP_TABLE.cost_center%TYPE,
user_name XXX_COMP_TABLE.user_name%TYPE,
start_date XXX_COMP_TABLE.effective_start_date%TYPE,
end_date XXX_COMP_TABLE.effective_end_Date%TYPE
);
TYPE v_coll_rec IS TABLE OF my_rec INDEX BY PLS_INTEGER;
v_col1 v_coll_rec;
BEGIN
SELECT blob_content
INTO v_blob_data
FROM apex_application_temp_files
WHERE name = v_filename;
v_blob_len := DBMS_LOB.getlength (v_blob_data);
v_position := 1;
--wwv_flow.debug('v_position'||v_position);
LOOP
v_idx := DBMS_LOB.INSTR (v_blob_data, '0A', v_position);
-- wwv_flow.debug('v_idx'||v_idx);
IF v_idx = 0
THEN
wwv_flow.debug ('in if');
v_line :=
UTL_RAW.cast_to_varchar2 (
DBMS_LOB.SUBSTR (v_blob_data, 32767, v_position));
ELSE
-- wwv_flow.debug('in else');
v_line :=
UTL_RAW.cast_to_varchar2 (
DBMS_LOB.SUBSTR (v_blob_data, v_idx - v_position, v_position));
END IF;
wwv_flow.debug ('v_line' || v_line);
EXIT WHEN v_idx = 0;
v_position := v_idx + 1;
v_line := REPLACE (v_line, ',', ':');
v_data_array := wwv_flow_utilities.string_to_table (v_line);
IF (v_first_line_done != TRUE)
THEN
v_first_line_done := TRUE;
--wwv_flow.debug('v_data_array(5) '||v_data_array(5) );
IF v_data_array (1) = 'COMPANY_CODE'
AND v_data_array (2) = 'COST_CENTER_CODE'
AND v_data_array (3) = 'USER_NAME'
AND v_data_array (4) = 'EFFECTIVE_START_DATE' --AND v_data_array(5) = 'EFFECTIVE_END_DATE'
THEN
v_error_cd := 0;
ELSE
v_error_cd := 1;
END IF;
ELSIF (v_first_line_done = TRUE AND v_error_cd = 0)
THEN
FORALL indx IN 1 .. v_col1.COUNT
INSERT
into XXX_COMP_TABLE
VALUES v_col1 (indx);
END IF;
v_line := NULL;
v_sr_no := v_sr_no + 1;
END LOOP;
END;
【问题讨论】:
APEX 5 与此问题无关 - 已删除标签。 向我们展示您的forall
代码。没有理由将execute immediate
用于静态 SQL。
我正在尝试使用此代码通过 APEX 将大型 csv 文件上传到 db 表中。由于性能问题,我被要求使用 forall 语句调整此查询,但我不确定如何使用 forall 语句在这段代码中。我尝试过但无法在 forall 代码上进行开发,因为我仍然对如何插入 forall 语句感到困惑。你能指导我吗?
@Tony Andrews 我已经用 forall 语句修改了下面的代码,但由于其显示的 Count 必须声明为错误而无法正常工作-
我无法发布代码,因为它的 hwoing 太长 bt 2000 字符。我可以把代码发给你吗?
【参考方案1】:
DECLARE
v_blob_data BLOB;
v_blob_len NUMBER;
v_position NUMBER;
v_raw_chunk RAW(10000);
v_char CHAR(1);
c_chunk_len NUMBER := 1;
v_line VARCHAR2 (32767):= NULL;
v_data_array wwv_flow_global.vc_arr2;
v_rows NUMBER;
v_sr_no NUMBER := 1;
v_filename VARCHAR2(2000) := apex_util.get_session_state('P4_FILE_BROWSE' );
v_idx NUMBER;
v_first_line_done BOOLEAN := false;
v_error_cd NUMBER :=0;
TYPE my_rec IS RECORD ( company_code XXX_COMP_TABLE.company_code%type , cost_center XXX_COMP_TABLE.cost_center%type ,
user_name XXX_COMP_TABLE.user_name%type , start_date XXX_COMP_TABLE.effective_start_date%type, end_date XXX_COMP_TABLE.effective_end_Date%type);
TYPE v_coll_rec IS TABLE OF my_rec INDEX BY PLS_INTEGER;
BEGIN
SELECT blob_content
INTO v_blob_data
FROM apex_application_temp_files
WHERE name = v_filename;
v_blob_len := dbms_lob.getlength(v_blob_data);
v_position := 1;
--wwv_flow.debug('v_position'||v_position);
LOOP
v_idx := dbms_lob.instr( v_blob_data, '0A', v_position );
-- wwv_flow.debug('v_idx'||v_idx);
IF v_idx = 0 THEN
wwv_flow.debug('in if');
v_line := utl_raw.cast_to_varchar2( dbms_lob.substr( v_blob_data, 32767, v_position ) );
ELSE
-- wwv_flow.debug('in else');
v_line := utl_raw.cast_to_varchar2( dbms_lob.substr( v_blob_data, v_idx - v_position, v_position ) );
END IF;
wwv_flow.debug('v_line'||v_line);
EXIT
WHEN v_idx = 0;
v_position := v_idx + 1;
v_line := REPLACE (v_line, ',', ':');
v_data_array := wwv_flow_utilities.string_to_table (v_line);
IF(v_first_line_done != true) THEN
v_first_line_done := true;
--wwv_flow.debug('v_data_array(5) '||v_data_array(5) );
IF v_data_array(1) = 'COMPANY_CODE' AND v_data_array(2) = 'COST_CENTER_CODE' AND v_data_array(3) = 'USER_NAME'
AND v_data_array(4) = 'EFFECTIVE_START_DATE' --AND v_data_array(5) = 'EFFECTIVE_END_DATE'
THEN
v_error_cd := 0;
ELSE
v_error_cd := 1;
END IF;
ELSIF(v_first_line_done = true AND v_error_cd = 0) THEN
FORALL indx IN 1 .. v_coll_rec.COUNT
INSERT INTO
( SELECT company_code,
cost_center,
user_name ,
start_date,
end_date
FROM XXX_COMP_TABLE
)
VALUES v_coll_rec (indx) ;
END IF;
v_line := NULL; v_sr_no := v_sr_no + 1;
END LOOP;
END;
【讨论】:
你忘了删除v_col1 v_coll_rec;
创建的那个类型的变量,直接使用了错误的类型。将此添加到声明中,并将代码中所有位置的v_coll_rec
替换为v_col1
。也插入是错误的
@XING 感谢您验证代码。插入语句显示错误 - PL/SQL: ORA-00947: not enough values
检查我上面的回答。我已根据您发布的代码更正它
@XING 对不起,我看不到你的答案。代码仍然没有显示足够的值。以上是关于如何在 APEX 应用程序的 csv 文件的批量数据插入中使用 forall 语句的主要内容,如果未能解决你的问题,请参考以下文章
Oracle APEX - 将隐藏的 SQL 查询下载到 CSV
如何批量读取csv格式的文件名及文件内容到新的Excel中?