2013-11-04 48 views
0

我已经在pl/sql中编写了一个自定义函数,它根据提供的分隔符将clob变量拆分为一组字符串,但它不能按预期工作,请帮助我用代码来解决问题。自定义拆分功能不能在pl/sql中工作

create or replace 
FUNCTION        SPLITCLOB (p_in_string clob, p_delim VARCHAR2) RETURN t_array 
IS 
    i  number :=0; 
    pos  number :=0; 
    lv_str clob := p_in_string; 

    Strings t_array:=t_array(); 
Begin 
    -- determine first chuck of string 
    pos := DBMS_LOB.INSTR(lv_str,p_delim,1,1); 

    If (pos = 0) Then 
    i := i + 1; 
    strings.Extend(); 
    strings(i) := DBMS_LOB.SUBSTR(lv_str,1); 
    RETURN strings; 
    End If; 
    -- while there are chunks left, loop 
    WHILE (pos != 0) LOOP 
    -- increment counter 
    i := i + 1; 

    -- create array element for chuck of string 
    strings.EXTEND(); 
    strings(i) := DBMS_LOB.SUBSTR(lv_str,1,pos-1); 

    -- remove chunk from string 
    lv_str := DBMS_LOB.SUBSTR(lv_str,pos+1,dbms_lob.getLength(lv_str)); 

    -- determine next chunk 
    pos := DBMS_LOB.INSTR(lv_str,p_delim,1,1); 

    -- no last chunk, add to array 
    IF pos = 0 THEN 
     strings.extend(); 
     strings(i+1) := lv_str; 
    END IF; 
    End Loop; 

    -- return array 
    RETURN strings; 
End Splitclob; 

这里t_array()是自定义类型defiition其中在预先设置

create or replace 
    TYPE "T_ARRAY" 
    AS TABLE OF VARCHAR2(500); 

感谢以下

+1

代码有什么问题? 你有什么试图解决它? 您尝试从中提取数据的CLOB的内容是什么? – Rene

+0

有一张表,其中有一个名为description的列,其中clob作为内容,基本上它包含我们用于分析的应用程序的audit_logs。在表中的描述是种类“order_id = 383325; order_line_item = 59; order_class_id = 5749; subscription_code = 5U12PFNCAU; start_date = 01/12/2012; end_date = 30/11/2013; date_override = null; license_available = -1; license_consumed = 1; license_override = -1; order_class_status = 0“ – Abhi

+0

我们试图通过提供分隔符来获取各种值”;“ 。 – Abhi

回答

1

我很久以前改变了一段代码,我写的不是,似乎它可以按照你的想法工作。注意:如果输入参数中只有一个项目(我的意思是输入中没有分隔符的情况),它也可以工作。

CREATE OR REPLACE 
    TYPE T_ARRAY 
    AS TABLE OF VARCHAR2(500); 
/

CREATE OR REPLACE FUNCTION splitclob (p_clob_in CLOB, p_delim VARCHAR2) RETURN t_array 
AS 
    v_buffer VARCHAR2(500); 
    v_len NUMBER; 
    v_offset NUMBER := 1; 
    v_delim_pos NUMBER; 
    v_amount NUMBER; 
    v_result_array t_array := t_array(); 
BEGIN 
    IF p_clob_in IS NOT NULL THEN 
    v_len := dbms_lob.getlength(p_clob_in); 

    WHILE v_offset < v_len 
    LOOP 
     v_delim_pos := instr(p_clob_in, p_delim, v_offset); 

     IF v_delim_pos = 0 THEN 
     v_amount := v_len - v_offset + 1; 
     ELSE 
     v_amount := v_delim_pos - v_offset; 
     END IF; 

     dbms_lob.read(p_clob_in, v_amount, v_offset, v_buffer); 
     v_offset := v_offset + v_amount + 1; 

     v_result_array.EXTEND; 
     v_result_array(v_result_array.LAST) := v_buffer; 
    END LOOP; 
    END IF; 

    RETURN v_result_array; 
END; 
/

DECLARE 
    v_array t_array; 
BEGIN 
    v_array := splitclob('order_id=383325; order_line_item=59; order_class_id=5749; subscription_code=5U12PFNCAU; start_date=01/12/2012; end_date=30/11/2013; date_override=null; license_available=-1; license_consumed=1; license_override=-1; order_class_status=0', ';'); 

    FOR v_i IN v_array.first..v_array.last 
    LOOP 
    dbms_output.put_line(v_i || ' ' || v_array(v_i)); 
    END LOOP; 
END; 
/

输出:

1 order_id=383325 
2 order_line_item=59 
3 order_class_id=5749 
4 subscription_code=5U12PFNCAU 
5 start_date=01/12/2012 
6 end_date=30/11/2013 
7 date_override=null 
8 license_available=-1 
9 license_consumed=1 
10 license_override=-1 
11 order_class_status=0

你必须要考虑到的情况时的标记之一将是超过500个字符。请记住,SQL上下文中的VARCHAR2数据类型具有4000字节的限制。如果你知道不会有比这更长的令牌,那么你不需要改变任何东西。

+0

在SQL,4000字节或字符中使用时不是限制Oracle VARCHAR2吗?来源:http://docs.oracle.com/cd/E11882_01/server.112/e41085/sqlqr06002.htm#SQLQR966 –

+0

@IanCarpenter我想我把标准输出的最大行长度与VARCHAR2的最大长度以字节为单位混合起来,将会更新我的回答,谢谢。 –

+0

不用担心,并提高了您的答案 –