如何优化子串和& instring或替换函数进行调试

时间:2015-11-03 15:25:22

标签: plsql oracle11g plsqldeveloper



我编写了下面的存储过程,目的是读取移动到服务器上的逗号分隔文件(“DIR”文件夹),当执行脚本时,它实质上解析文件(.csv),并将数据分配给它各个变量(xJOB_ID,xCTRL_ID,xACCT_SEC,xCREATEDON_DATE)使我可以将数据插入表中。

我在Windows 7环境中使用Oracle SQL Developer版本4.0.0.13。幸运的是,在我的桌子上敲了几次代码后,我没有遇到任何运行脚本的问题。

文件的示例格式:
1111,2,T,10/10 / 2000
2222,12345,U,10/10 / 2001
5555,123,S,10/10 / 1999

我的问题: 我发现使用SUBSTRING& amp; INSTRING函数用于解析数据,并想知道如何改进脚本,以便在需要调试的情况下,可以很容易地解决没有编写存储过程的人。

如果有意义,请告诉我。我给了你整个脚本,以便你能理解我想要完成的任务,以便我可以改进代码以便进行调试。

create or replace PROCEDURE SP_INSERT_INTO_TABLE(xFILE_NAME IN VARCHAR2)

IS 


--UTL_FILE is an oracle package that allows you to read and write operating system files. 

TEXT_DATA UTL_FILE.FILE_TYPE;

v_ROW_LENGTH    NUMBER := 1024;
v_TEXTSTRING    VARCHAR2(4000);
cLINE           VARCHAR2(100);
xJOB_ID         NUMBER;
xCTRL_ID        NUMBER;
xACCT_SEC       VARCHAR2(1);
xCREATEDON_DATE DATE;
xCOUNT          NUMBER := 0;

BEGIN
    BEGIN
    --Streams in the file data and assigns it to TEXT_DATA variable. 
    TEXT_DATA := UTL_FILE.FOPEN('DIR', xFILE_NAME, 'R', v_ROW_LENGTH);      
END;

--Begin LOOP to get each line and assign to cLINE to extract, assign to each variable, and insert into the table
LOOP    
    BEGIN
        --Gets each string/line up to the line terminator
        UTL_FILE.GET_LINE(TEXT_DATA, v_TEXTSTRING);
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            EXIT;
    END;

    --Each line is assigned to the variable cLINE.
    cLINE := v_TEXTSTRING;

    --Begin to parse data using SUBSTRING and INSTRING functions
    BEGIN        
        --Extracts string from cLINE position 1 up to the first occurrence, converts it to a number, and assigns it to the variable. 
        xJOB_ID         := TO_NUMBER(SUBSTR(cLINE, 1,INSTR(cLINE, ',', 1, 1)-1));

        --Extracts string from cLINE between the 1st and 2nd occurrence, converts it to a number, and assigns it to the variable.
        xCTRL_ID        := TO_NUMBER(SUBSTR(cLINE, INSTR(cLINE, ',', 1, 1)+1, INSTR(cLINE, ',', 1,2)-INSTR(cLINE, ',', 1,1)-1));

        --Extracts string from cLINE between the 2nd and 3rd occurrence and assigns it to the variable.
        xACCT_SEC       := SUBSTR(cLINE, INSTR(cLINE, ',', 1, 2) +1, INSTR(cLINE, ',', 1,3)-INSTR(cLINE, ',', 1,2) -1);  

        --Extracts string from cLINE after the last occurrence, converts it to a date, and assigns it the variable.
        xCREATEDON_DATE := TO_DATE(SUBSTR(cLINE, INSTR(cLINE, ',', 1, 3)+1), 'MM/DD/YYYY');

        INSERT INTO TABLE(JOB_ID, CTRL_ID, ACCT_SEC, CREATEDON_DATE)
        VALUES(xJOB_ID, xCTRL_ID, xACCT_SEC, xCREATEDON_DATE);
        COMMIT;

        --Counter to count the amount of inserts
        xCOUNT := xCOUNT + 1;

    EXCEPTION
        --Exception to handle the conversion of a string to a NUMBER or value is longer than the declared length of the variable.
        WHEN VALUE_ERROR THEN 
        NULL;

    END;        
END LOOP;

DBMS_OUTPUT.PUT_LINE('RECORDS INSERTED: ' || xCOUNT);    
UTL_FILE.FCLOSE(TEXT_DATA);

END;

1 个答案:

答案 0 :(得分:2)

您可以使用REGEXP_SUBSTR,因为它只需要一个函数调用,而不是一系列SUBSTR和INSTR调用,例如:

(由Gary_W提供):

declare
  v_str varchar2(20) := 'a,,bcd';
  v_substr1 varchar2(10);
  v_substr2 varchar2(10);
  v_substr3 varchar2(10);
begin
  v_substr1 := regexp_substr(v_str, '([^,]*)(,|$)', 1, 1, NULL, 1);
  v_substr2 := regexp_substr(v_str, '([^,]*)(,|$)', 1, 2, NULL, 1);
  v_substr3 := regexp_substr(v_str, '([^,]*)(,|$)', 1, 3, NULL, 1);
  dbms_output.put_line(v_substr1||':'||v_substr2||':'||v_substr3);
end;
/

a::bcd

如上所示,上述内容适用于具有空部分的字符串。搜索模式已分为两组(也称为子表达式):[^,]*,|$

第一组说:任何不是逗号([^,])的字符出现0次或更多次(*)。

第二组说:逗号或行尾。

所以整个模式正在查找一组除逗号之外的任何字符,这些逗号可能存在​​也可能不存在,后面跟逗号或行尾。

regexp_substr中的最后一个参数表示我们要从搜索模式中选择要显示的第一个子表达式 - 如果我们不包含这个,那么你最终会将逗号显示为字符串的一部分被退回。

如果您完全确定该字符串的所有元素都不为null,则以下内容将起作用:

declare
  v_str varchar2(20) := 'a,123,bcd';
  v_substr1 varchar2(10);
  v_substr2 varchar2(10);
  v_substr3 varchar2(10);
begin
  v_substr1 := regexp_substr(v_str, '[^,]+', 1, 1);
  v_substr2 := regexp_substr(v_str, '[^,]+', 1, 2);
  v_substr3 := regexp_substr(v_str, '[^,]+', 1, 3);
  dbms_output.put_line(v_substr1||':'||v_substr2||':'||v_substr3);
end;
/

a:123:bcd

这只是寻找指定出现的不是逗号的字符串,这比前一个例子中使用的搜索模式更容易理解(imho!),但是不那么健壮。