StringTokenizer in PL/SQL

In questo post indicherò due semplici modi per realizzare una function StringTokenizer in PL/SQL. Un primo modo e’ quello di utilizzare le espressioni regolari usando le function REGEXP_SUBSTR e REGEXP_INSTR fornite da Oracle. Le Function REGEXP_SUBSTR e REGEXP_INSTR non sono altro che l’estensione delle rispettive function SUBSTR e INSTR di Oracle. La function STRINGTOKENIZER_REGEX, che potete vedere sotto, si comporta come la classe StringTokenizer in Java, cioè’ eliminando tutti i token che sono a NULL. Il risultato finale sara’ un DBMS_SQL.varchar2_table con tutti i token validi. Vediamo, adesso, il codice:

CREATE OR REPLACE
FUNCTION STRINGTOKENIZER_REGEX
    (p_string IN LONG, p_separators IN VARCHAR2)
RETURN DBMS_SQL.varchar2_table
IS
    l_token_tbl DBMS_SQL.varchar2_table;
    pattern     VARCHAR2(250);
    param_clob  CLOB;
BEGIN
    param_clob := TO_CLOB(p_string);
    pattern := '[^(' || p_separators || ')]+' ;
        SELECT   REGEXP_SUBSTR (param_clob, pattern, 1, LEVEL) token
          BULK   COLLECT
          INTO   l_token_tbl
          FROM   DUAL
         WHERE   REGEXP_SUBSTR (param_clob, pattern, 1, LEVEL) IS NOT NULL
    CONNECT BY   REGEXP_INSTR (param_clob, pattern, 1, LEVEL) > 0;
    RETURN l_token_tbl;
EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line('STRINGTOKENIZER_REGEX - Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
        dbms_output.put_line(DBMS_UTILITY.format_error_backtrace);
        RAISE;
END STRINGTOKENIZER_REGEX;
/

Si può’ fare la stessa cosa, vista sopra, senza usare le espressioni regolari usando direttamente le funzioni di SUBSTR e INSTR di Oracle. In questo caso la funzione PL/SQL STRINGTOKENIZER scritta sotto restituisce sempre un DBMS_SQL.varchar2_table ma con anche i token NULL. Vediamo il codice:

CREATE OR REPLACE
FUNCTION STRINGTOKENIZER
    (p_string IN LONG, p_separators IN VARCHAR2)
RETURN DBMS_SQL.varchar2_table
IS
    l_token_tbl DBMS_SQL.varchar2_table;
    l_start NUMBER;
    l_pos NUMBER;
    l_index NUMBER;
BEGIN
    l_start := 1;
    l_pos :=1;
    l_index:=1;
    WHILE TRUE LOOP
        l_pos := INSTR (p_string ,p_separators ,l_start);
        IF l_start > LENGTH(p_string) THEN
        EXIT;
        END IF;
        IF l_pos = 0 THEN
        l_token_tbl(l_index):=Substr(p_string ,l_start, LENGTH(p_string)+1-l_start);
        EXIT;
        END IF;
        l_token_tbl(l_index):=Substr(p_string ,l_start, l_pos-l_start);
        l_start:=l_pos+LENGTH(p_separators);
        l_index:=l_index+1;
    END LOOP;
    RETURN l_token_tbl;
EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line('STRINGTOKENIZER - Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
        dbms_output.put_line(DBMS_UTILITY.format_error_backtrace);
        RAISE;
END STRINGTOKENIZER;
/

Scriviamo adesso uno script PL/SQL per testare le nostre function:

DECLARE
ret DBMS_SQL.VARCHAR2_TABLE;
BEGIN
-- Now call the stored program
  ret := STRINGTOKENIZER('aaa|bbb|ccc|ddd|eeee|','|');
-- Output the results
IF ret IS NOT NULL THEN
 IF ret.count > 0 THEN
   FOR i IN ret.first..ret.last LOOP
     IF ret.exists(i) THEN
       null; -- type of data not known
dbms_output.put_line(SubStr('ret('||TO_CHAR(i)||') = '||ret(i),1,255));
      END IF;
    END LOOP;
  END IF;
 END IF;
EXCEPTION
WHEN OTHERS THEN
  dbms_output.put_line(SubStr('Error '||TO_CHAR(SQLCODE)||': '||SQLERRM, 1, 255));
  dbms_output.put_line(dbms_utility.format_error_backtrace);
RAISE;
END;

Il test di sopra e’ relativo alla function STRINGTOKENIZER ma e’ facilmente m. Per concludere entrambe le funzioni sembrano funzionare perfettamente. L’unica differenza come gia’ detto e’ relative ai token a NULL per quanto riguarda l’output. C’e’ pero’ un’altra differenza che e’ relativa alle performance, l’uso infatti delle espressioni regolari e’ infatti meno performante nel caso di stringhe molto lunghe da parsificare.

0 comments ↓

There are no comments yet...Kick things off by filling out the form below.

Leave a Comment