Home > Back-end >  Extract information from a string that is not delimited but has break lines PL/SQL
Extract information from a string that is not delimited but has break lines PL/SQL

Time:01-05

I am working on a function which of the following string:

create or replace PROCEDURE get_error_keys(p_error_code IN VARCHAR2) IS
    v_error_key varchar2(2000):= '
EF03   There are disabled accounts
EF04   The account is invalid. Check your cross validation rules and segment values
EF05   There is no account with this account combination ID
EF06   The alternate account is invalid
WF01   An alternate account was used instead of the original account
WF02   A suspense account was used instead of the original account';
v_linea              VARCHAR2(32767);
    --
--
Begin
    
   SELECT
    regexp_substr(v_error_key_list, '[^('||chr(13)||chr(10)||')] ',1,level) Linea into v_linea
FROM
    dual
CONNECT BY
    regexp_substr(v_error_key_list, '[^('||chr(13)||chr(10)||')] ',1,level) IS NOT NULL;
    
End;

My intention is to filter this query, which receives p_error_code and filters by that parameter, for example:

If p_error_code = 'EF04', then the query returns: EF04 The account is invalid. Check your cross validation rules and segment values

I have modified the query to add a where condition:

select
     regexp_substr(v_error_key, '[^('||chr(13)||chr(10)||')] ',1,level) Line into v_line
DESDE
     dual
WHERE Line like '%'||p_error_code||'%'
CONNECT BY
     regexp_substr(v_error_key, '[^('||chr(13)||chr(10)||')] ',1,level) IS NOT NULL;

But I get the following error: 7/18 PL/SQL: ORA-00904: "Linea": invalid identifier

Thanks, Cesar.

CodePudding user response:

As I said in the comment, the right way is to put the code/descriptions in a table and then do a simple lookup. But since I'm sitting in a meeting and can play with this...it can be simplified by treating the string of error/descriptions as a delimited string with a chr(10) character as the delimiter. Get the substring that starts with the error code passed in, followed by one or more whitespace characters, then zero or more any characters non-greedy until the delimiter or the end of the line.

SELECT
REGEXP_SUBSTR(v_error_key_list, '('||p_error_code||'\s .*?)('||CHR(10)||'|$)')
INTO v_linea

But at least do this for easier maintenance if you can't create a proper lookup table for some reason. Use a WITH clause to put your codes/descriptions in a table form. Best practice is to always allow for the exception where your code is not found also.

BEGIN
  WITH tbl_err(code, DESCR) AS (
    SELECT 'EF03', 'There are disabled accounts' FROM dual UNION ALL
    SELECT 'EF04', 'The account is invalid. Check your cross validation rules and segment values' FROM dual UNION ALL
    SELECT 'EF05', 'There IS NO ACCOUNT WITH this ACCOUNT combination ID' FROM dual UNION ALL
    SELECT 'EF06', 'The alternate account is invalid' FROM dual UNION ALL
    SELECT 'WF01', 'An alternate ACCOUNT was used INSTEAD OF THE original ACCOUNT' FROM dual UNION ALL
    SELECT 'WF02', 'A suspense account was used instead of the original account' FROM dual
  )
  SELECT DESCR
  INTO v_linea
  FROM tbl_err
  WHERE code = p_error_code;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      v_linea := 'Code: ' || p_error_code || ' not found.';
  END;
  

CodePudding user response:

It would really be best to put the error codes and error texts into some sort of lookup table. Below is a function that meets your requirements with a hard-coded string containing multiple error codes.

create or replace FUNCTION get_error_keys(p_error_code IN VARCHAR2) 
RETURN VARCHAR2
IS
    v_error_key_list varchar2(2000):= '
EF03   There are disabled accounts
EF04   The account is invalid. Check your cross validation rules and segment values
EF05   There is no account with this account combination ID
EF06   The alternate account is invalid
WF01   An alternate account was used instead of the original account
WF02   A suspense account was used instead of the original account';
    --
--
Begin
    
   RETURN REGEXP_SUBSTR(v_error_key_list, p_error_code || '\s [^' || CHR(10) ||'$] ');
    
End;

Below is code to test the function.

DECLARE

  TYPE t_input_value_tbl IS TABLE OF VARCHAR2(4);
  l_input_value_tbl t_input_value_tbl;
  l_return_value VARCHAR2(32767);

BEGIN

  l_input_value_tbl := t_input_value_tbl('EF03','EF04','EF05','EF06','WF01','WF02','ZZ01');

  FOR i IN l_input_value_tbl.FIRST..l_input_value_tbl.LAST LOOP
  
    l_return_value := get_error_keys(l_input_value_tbl(i));
    dbms_output.put_line('input: "' || l_input_value_tbl(i) || '" l_return_value: "' || l_return_value || '"');
  
  END LOOP;

END;
Results
input: "EF03" l_return_value: "EF03 There are disabled accounts"
input: "EF04" l_return_value: "EF04 The account is invalid. Check your cross validation rules and segment values"
input: "EF05" l_return_value: "EF05 There is no account with this account combination ID"
input: "EF06" l_return_value: "EF06 The alternate account is invalid"
input: "WF01" l_return_value: "WF01 An alternate account was used instead of the original account"
input: "WF02" l_return_value: "WF02 A suspense account was used instead of the original account"
input: "ZZ01" l_return_value: ""
  • Related