2017-02-02 1 views
0

Я хочу написать функцию, которая принимает входную строку, использует REGEXP_SUBSTR для синтаксического анализа этой строки до пяти подстрок и возвращает подстроки в процедуру, называемую функция.Функция для принятия строкового параметра и возвращаемых подстрок, используемых вне функции

CREATE OR REPLACE FUNCTION PARSER_FUNCTION 
(inputString IN VARCHAR2) 
RETURN VARCHAR2 
AS 
subStrings VARCHAR2(100); 
CURSOR C1 IS 
SELECT REGEXP_SUBSTR(inputString, '[[:alpha:]]+', 1, 1) 
    , REGEXP_SUBSTR(inputString, '[[:alpha:]]+', 1, 2) 
    , REGEXP_SUBSTR(inputString, '[[:alpha:]]+', 1, 3) 
    , REGEXP_SUBSTR(inputString, '[[:alpha:]]+', 1, 4) 
    , REGEXP_SUBSTR(inputString, '[[:alpha:]]+', 1, 5) 
    FROM DUAL; 
BEGIN 
OPEN C1; 
/* Not sure what to do here... */ 
RETURN subStrings; 
END; 
END PARSER_FUNCTION; 

В предложении WHERE хранимой процедуры, которая вызывает эту функцию, я хочу, чтобы иметь возможность сравнить столбец каждой из пяти подстрок, что-то вроде:

WHERE table_column LIKE '%' || PARSER_FUNCTION[1] || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION[2] || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION[3] || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION[4] || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION[5] || '%' 

Как это можно сделать это?

ответ

1
CREATE OR REPLACE FUNCTION PARSER_FUNCTION(
    inputString IN VARCHAR2, 
    index  IN NUMBER 
) 
RETURN VARCHAR2 DETERMINISTIC 
AS 
    RETURN REGEXP_SUBSTR(inputString, '[[:alpha:]]+', 1, index); 
END PARSER_FUNCTION; 
/

Или, без регулярных выражений:

CREATE OR REPLACE FUNCTION parser_function(
    list  IN VARCHAR2, 
    position IN NUMBER, 
    delimiter IN VARCHAR2 DEFAULT ',' 
) 
RETURN VARCHAR2 DETERMINISTIC 
IS 
    p_start NUMBER := 1; 
    p_end NUMBER; 
BEGIN 
    IF list IS NULL OR position < 1 THEN 
    RETURN NULL; 
    END IF; 
    IF position > 1 THEN 
    p_start := INSTR(list, delimiter, 1, position - 1) + 1; 
    IF p_start = 1 THEN 
     RETURN NULL; 
    END IF; 
    END IF; 
    p_end := INSTR(list, delimiter, 1, position); 
    IF p_end = 0 THEN 
    p_end := LENGTH(list) + 1; 
    END IF; 
    RETURN SUBSTR(list, p_start, p_end - p_start); 
END; 
/

Тогда вы можете просто сделать:

WHERE table_column LIKE '%' || PARSER_FUNCTION('list,list2,list3', 1) || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION('list,list2,list3', 2) || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION('list,list2,list3', 3) || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION('list,list2,list3', 4) || '%' 
    AND table_column LIKE '%' || PARSER_FUNCTION('list,list2,list3', 5) || '%' 

(Примечание: Это будет работать, если вы используете AND в ИНЕКЕ но не может, когда вы используете OR, так как 4-й и 5-й записи в списке не существуют, поэтому вы получите предложение AND table_column LIKE '%%' wh Ich всегда будет истинным, так что вам может понадобиться немного более оборонительный кодирование, чтобы проверить, если возврат из PARSER_FUNCTION не NULL)

Или вы могли бы просто избавиться от функции:.

WHERE table_column LIKE '%' || REGEXP_SUBSTR('list,list2,list3', '[[:alpha:]]+', 1, 1) || '%' 
    AND table_column LIKE '%' || REGEXP_SUBSTR('list,list2,list3', '[[:alpha:]]+', 1, 2) || '%' 
    AND table_column LIKE '%' || REGEXP_SUBSTR('list,list2,list3', '[[:alpha:]]+', 1, 3) || '%' 
    AND table_column LIKE '%' || REGEXP_SUBSTR('list,list2,list3', '[[:alpha:]]+', 1, 4) || '%' 
    AND table_column LIKE '%' || REGEXP_SUBSTR('list,list2,list3', '[[:alpha:]]+', 1, 5) || '%' 

Обновление:

Вы также можете конвертировать список коллекции и присоединиться, что ваш запрос:

CREATE OR REPLACE FUNCTION split_String(
    i_str IN VARCHAR2, 
    i_delim IN VARCHAR2 DEFAULT ',' 
) RETURN SYS.ODCIVARCHAR2LIST DETERMINISTIC 
AS 
    p_result  SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(); 
    p_start  NUMBER(5) := 1; 
    p_end   NUMBER(5); 
    c_len CONSTANT NUMBER(5) := LENGTH(i_str); 
    c_ld CONSTANT NUMBER(5) := LENGTH(i_delim); 
BEGIN 
    IF c_len > 0 THEN 
    p_end := INSTR(i_str, i_delim, p_start); 
    WHILE p_end > 0 LOOP 
     p_result.EXTEND; 
     p_result(p_result.COUNT) := SUBSTR(i_str, p_start, p_end - p_start); 
     p_start := p_end + c_ld; 
     p_end := INSTR(i_str, i_delim, p_start); 
    END LOOP; 
    IF p_start <= c_len + 1 THEN 
     p_result.EXTEND; 
     p_result(p_result.COUNT) := SUBSTR(i_str, p_start, c_len - p_start + 1); 
    END IF; 
    END IF; 
    RETURN p_result; 
END; 
/

Тогда вы можете просто сделать:

SELECT * 
FROM your_table t 
WHERE NOT EXISTS(SELECT 1 
        FROM TABLE(split_String('list1,list2,list3') l 
        WHERE t.table_column NOT LIKE '%' || l.COLUMN_VALUE || '%') 

Это означает, что ваш список может содержать любое количество элементов, и он будет проверять их все без неоднократно называть извлечение элемента списка с помощью регулярных выражений.

+0

Мне нужно было вызвать функцию из четырех разных хранимых процедур. Я заставлял себя думать, что в любое время, когда мне нужно использовать процесс более одного раза, мне нужно модулизировать процесс. Еще раз взглянув на мою проблему, я думаю, что избавление от этой функции было правильным. Большое спасибо. – Jake

+0

Ваше регулярное выражение не работает с элементом списка NULL, но возвращает неправильное значение.Попробуйте, где ожидается третий элемент «listC», а второй элемент - NULL: 'с tbl (col1) as ( выберите« listA ,, listC, listD »из двойного ) выберите REGEXP_SUBSTR (col1, '[[[ : alpha:]] + ', 1, 3) от tbl; ' –

+0

Итак, вы бы исправили регулярное выражение один раз, в своей функции или много раз по всему вашему коду? Придерживайтесь своего первоначального инстинкта! –

0

Рассмотрим эту функцию:

FUNCTION GET_LIST_ELEMENT(string_in VARCHAR2, element_in NUMBER, delimiter_in VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS 
    BEGIN 
     RETURN REGEXP_SUBSTR(string_in, '(.*?)(\'||delimiter_in||'|$)', 1, element_in, NULL, 1); 
    END GET_LIST_ELEMENT; 

Как найти в этом посте:

https://stackoverflow.com/a/25652018/2543416

Пожалуйста см, что нить для обсуждения, которые могут предоставить некоторую информацию для вас.

+0

Для подстрок это регулярное выражение прекрасно, но не использовать его для подсчета количества элементов: 'SELECT REGEXP_COUNT ('1,2,3', '(. *?) (\, | $)') FROM DUAL: 'Он будет считать один слишком много, но не всегда:' SELECT REGEXP_COUNT ('1,2,3,', '(. *?) (\, | $)') FROM DUAL; ' – MT0

+0

@ MT0 Отличное наблюдение! Для подсчета элементов я обычно использую 'REGEXP_COUNT ('1,2', ',') + 1' (подсчитываем разделители и добавляем 1). –

Смежные вопросы