SQL中引发异常后如何继续while循环
Posted
技术标签:
【中文标题】SQL中引发异常后如何继续while循环【英文标题】:How to continue while loop after exception raised in SQL 【发布时间】:2014-07-17 20:01:19 【问题描述】:在下面的代码中引发异常后,我将如何继续 while 循环?
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_first_line_done boolean := false;
v_error_cd number :=0;
v_quote_pos1 NUMBER;
v_quote_pos2 NUMBER;
v_enclosed_str VARCHAR(200);
v_errmsg VARCHAR2(4000);
BEGIN
delete from TEMP_MM_UPDATE where username = :P1_USER_ID;
-- Read data from wwv_flow_files</span>
select
blob_content
into v_blob_data
from wwv_flow_files
where name = :P2_FILE_UPLOAD;
v_blob_len := dbms_lob.getlength(v_blob_data);
v_position := 1;
-- Read and convert binary to char</span>
WHILE ( v_position <= v_blob_len )
LOOP
begin
v_raw_chunk := dbms_lob.substr(v_blob_data,c_chunk_len,v_position);
v_char := chr(hex_to_decimal(rawtohex(v_raw_chunk)));
v_line := v_line || v_char;
v_position := v_position + c_chunk_len;
-- When a whole line is retrieved </span>
IF v_char = CHR(10) THEN
LOOP
--Make sure there's something to replace
IF INSTR(v_line, '"', 1, 1) = 0 THEN
EXIT; -- If nothing to replace, exit loop and don't try
END IF;
--Find the position of the first and second quotes in the line of text
v_quote_pos1 := INSTR(v_line, '"', 1, 1);
v_quote_pos2 := INSTR(v_line, '"', 1, 2);
--Extract the inner string
v_enclosed_str := SUBSTR(v_line, v_quote_pos1 + 1, v_quote_pos2 - v_quote_pos1 - 1);
--perform the replacement
v_line := SUBSTR(v_line, 0, v_quote_pos1 - 1) || REPLACE(v_enclosed_str, ',', '<') || SUBSTR(v_line, v_quote_pos2 + 1);
END LOOP;
-- Convert comma to : to use wwv_flow_utilities </span>
v_line := REPLACE (v_line, ',', ':');
v_line := REPLACE (v_line, '<', ',');
v_line := REPLACE (trim(v_line), '-', NULL);
--v_line := REPLACE (trim(v_line), '"', NULL);
-- Convert each column separated by : into array of data </span>
v_data_array := wwv_flow_utilities.string_to_table (v_line);
--Check to see if the row of column headers has already been parsed through
IF(v_first_line_done != true)THEN
v_first_line_done := true;
--Check column order in spreadsheet
IF(v_data_array(1) LIKE '%Username%' AND
v_data_array(2) LIKE '%NDN%' AND
v_data_array(3) LIKE '%PCFN%') THEN
v_error_cd := 0;
v_line := NULL;
ELSE
v_error_cd := 1;
END IF;
--If first line is done and the column order is correct then
ELSIF(v_first_line_done = true AND v_error_cd = 0) THEN
-- Insert data into target table </span>
EXECUTE IMMEDIATE 'insert into TEMP_MM_UPDATE
(USERNAME,
RPT_FLAG,
PCFN)
values (:1,:2,:3)'
USING
v_data_array(1),
v_data_array(2),
v_data_array(3);
-- Clear out
v_line := NULL; v_sr_no := v_sr_no + 1;
END IF;
END IF;
exception
WHEN OTHERS then
v_errmsg := SQLERRM;
insert into temp_mm_update (username,error_desc)
values (:P1_USER_ID, v_errmsg);
END;
END LOOP;
DELETE FROM WWV_FLOW_FILES where name = :P2_FILE_UPLOAD;
DELETE FROM TEMP_MM_UPDATE WHERE USERNAME IS NULL AND PCFN IS NULL;
IF(v_error_cd = 1) THEN
INSERT INTO temp_mm_update (USERNAME, ERROR_DESC)
VALUES (:P1_USER_ID, 'Error. Please check column order in spreadsheet.');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
insert into temp_mm_update (username,error_desc)
values (:P1_USER_ID, 'No Data Found.');
WHEN OTHERS then
v_errmsg := SQLERRM;
insert into temp_mm_update (username,error_desc)
values (:P1_USER_ID, v_errmsg);
END;
当我将异常放入上面的循环中时,该过程似乎永远不会完成,当我尝试删除表或类似的东西时,我最终会收到“NOWAIT”错误。
如果我在循环后立即取出“BEGIN”并取出循环内的异常,代码工作正常,但我希望能够指定每条记录有什么问题,而不是处理正确的记录,然后例如,在仅接受 6 的列中有 9 个值的记录后停止。
有人可以帮忙吗?
谢谢,
史蒂文
编辑: 我换了行: ELSIF(v_first_line_done = true AND v_error_cd = 0) 到 ELSIF(v_first_line_done = true AND v_error_cd = 0 AND (v_data_array(1) is not null OR v_data_array(1) not like '%-%')) 并且过程结束,但是当涉及到引发和异常的记录时,以下所有记录都有相同的异常。
我的 CSV 文件示例: 用户名 NDN PCFN DOOL0008 X 808461 DOOL0008 X 886332 DOOL0008 X 887223 DOOL0008 X 887992 DOOL0008 X 904959 DOOL0008 X 904959 DOOL0008 X 904968 DOOL0008 X 904968
例如,如果列 MM(其数据类型为 VARCHAR2(1))在第三条记录上的值为“XX”,则会引发该值太大的异常,然后是记录 4 -8 将引发相同的异常。
【问题讨论】:
在我看来,在最后一个END LOOP;
之前缺少一个 END;
语句。
@BobJarvis 抱歉,我忘了在此代码中添加它。在我实际使用的代码中,END;在 END LOOP 之前就在那里;
请在此处发布一些 blob_content 的示例内容,以便调试代码。
我用一些“逆向工程”数据尝试了你的代码,它工作正常。如果您的程序永远不会完成,那么这可能意味着您的程序最终陷入了无限循环。你的blob_content
的样本真的很有帮助。
@nop77svk 我用我的一些 CSV 文件数据编辑了我的帖子。希望这就是您所指的 blob_content。
【参考方案1】:
通过玩弄我的代码,我发现出了什么问题。 我需要将以下行添加到我的异常代码块中:
v_line := NULL; v_sr_no := v_sr_no + 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_first_line_done boolean := false;
v_error_cd number :=0;
v_quote_pos1 NUMBER;
v_quote_pos2 NUMBER;
v_enclosed_str VARCHAR(200);
v_errmsg VARCHAR2(4000);
BEGIN
delete from TEMP_MM_UPDATE where username = :P1_USER_ID;
-- Read data from wwv_flow_files</span>
select
blob_content
into v_blob_data
from wwv_flow_files
where name = :P2_FILE_UPLOAD;
v_blob_len := dbms_lob.getlength(v_blob_data);
v_position := 1;
-- Read and convert binary to char</span>
WHILE ( v_position <= v_blob_len )
LOOP
begin
v_raw_chunk := dbms_lob.substr(v_blob_data,c_chunk_len,v_position);
v_char := chr(hex_to_decimal(rawtohex(v_raw_chunk)));
v_line := v_line || v_char;
v_position := v_position + c_chunk_len;
-- When a whole line is retrieved </span>
IF v_char = CHR(10) THEN
LOOP
--Make sure there's something to replace
IF INSTR(v_line, '"', 1, 1) = 0 THEN
EXIT; -- If nothing to replace, exit loop and don't try
END IF;
--Find the position of the first and second quotes in the line of text
v_quote_pos1 := INSTR(v_line, '"', 1, 1);
v_quote_pos2 := INSTR(v_line, '"', 1, 2);
--Extract the inner string
v_enclosed_str := SUBSTR(v_line, v_quote_pos1 + 1, v_quote_pos2 - v_quote_pos1 - 1);
--perform the replacement
v_line := SUBSTR(v_line, 0, v_quote_pos1 - 1) || REPLACE(v_enclosed_str, ',', '<') || SUBSTR(v_line, v_quote_pos2 + 1);
END LOOP;
-- Convert comma to : to use wwv_flow_utilities </span>
v_line := REPLACE (v_line, ',', ':');
v_line := REPLACE (v_line, '<', ',');
v_line := REPLACE (trim(v_line), '-', NULL);
--v_line := REPLACE (trim(v_line), '"', NULL);
-- Convert each column separated by : into array of data </span>
v_data_array := wwv_flow_utilities.string_to_table (v_line);
--Check to see if the row of column headers has already been parsed through
IF(v_first_line_done != true)THEN
v_first_line_done := true;
--Check column order in spreadsheet
IF(v_data_array(1) LIKE '%Username%' AND
v_data_array(2) LIKE '%NDN%' AND
v_data_array(3) LIKE '%PCFN%') THEN
v_error_cd := 0;
v_line := NULL;
ELSE
v_error_cd := 1;
END IF;
--If first line is done and the column order is correct then
ELSIF(v_first_line_done = true AND v_error_cd = 0) THEN
-- Insert data into target table </span>
EXECUTE IMMEDIATE 'insert into TEMP_MM_UPDATE
(USERNAME,
RPT_FLAG,
PCFN)
values (:1,:2,:3)'
USING
v_data_array(1),
v_data_array(2),
v_data_array(3);
-- Clear out
v_line := NULL; v_sr_no := v_sr_no + 1;
END IF;
END IF;
exception
WHEN OTHERS then
v_errmsg := SQLERRM;
insert into temp_mm_update (username,error_desc)
values (:P1_USER_ID, v_errmsg);
v_line := NULL; v_sr_no := v_sr_no + 1;
END;
END LOOP;
DELETE FROM WWV_FLOW_FILES where name = :P2_FILE_UPLOAD;
DELETE FROM TEMP_MM_UPDATE WHERE USERNAME IS NULL AND PCFN IS NULL;
IF(v_error_cd = 1) THEN
INSERT INTO temp_mm_update (USERNAME, ERROR_DESC)
VALUES (:P1_USER_ID, 'Error. Please check column order in spreadsheet.');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
insert into temp_mm_update (username,error_desc)
values (:P1_USER_ID, 'No Data Found.');
WHEN OTHERS then
v_errmsg := SQLERRM;
insert into temp_mm_update (username,error_desc)
values (:P1_USER_ID, v_errmsg);
END;
【讨论】:
以上是关于SQL中引发异常后如何继续while循环的主要内容,如果未能解决你的问题,请参考以下文章
我的 do while 循环在一次迭代后停止。我该如何继续下去?
在MATLAB中如何实现一段while循环后,判断是不是符合条件,若不符合重新回到while?