2017-02-02 1 views
0

Ich möchte eine Funktion schreiben, die eine Eingabezeichenfolge akzeptiert, REGEXP_SUBSTR verwendet, um diese Zeichenfolge in bis zu fünf Teilzeichenfolgen zu analysieren, und die Teilzeichenfolgen an die Prozedur zurückgibt, die das aufgerufen hat Funktion.Funktion zum Akzeptieren von String-Parameter und Rückgabe von außerhalb der Funktion verwendbaren Teilstrings

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; 

In der WHERE-Klausel der gespeicherten Prozedur, die diese Funktion aufruft, möchte ich in der Lage sein, eine Spalte zu jedem der fünf Teil zu vergleichen, so etwas wie:

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] || '%' 

Wie kann ich erreichen Dies?

Antwort

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; 
/

Oder ohne reguläre Ausdrücke:

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; 
/

Dann können Sie einfach tun:

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) || '%' 

(Anmerkung: Dies wird für die Arbeit, wenn Sie AND in der where-Klausel verwenden aber möglicherweise nicht, wenn Sie OR als 4. und 5. Einträge in der Liste verwenden nicht vorhanden sind, so erhalten Sie eine Klausel AND table_column LIKE '%%' WH ich werde immer wahr sein, so dass Sie ein bisschen mehr defensive Codierung benötigen könnte zu prüfen, ob die Rückkehr aus dem PARSER_FUNCTION ist nicht NULL)

Oder Sie könnten nur von der Funktion loszuwerden.

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) || '%' 

Update:

Sie auch die Liste in eine Sammlung umwandeln könnte und kommen, dass zu Ihrer Suchanfrage:

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; 
/

Dann können Sie einfach tun:

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 || '%') 

Dies bedeutet, dass Ihre Liste eine beliebige Anzahl von Elementen enthalten kann, und es wird überprüft sie alle ohne wiederholt aufrufen, um mit den Listeneintrag mit regulären Ausdrücken extrahieren.

+0

Ich musste die Funktion von vier verschiedenen gespeicherten Prozeduren aufrufen. Ich habe mich darauf konditioniert zu denken, dass ich jedes Mal, wenn ich einen Prozess mehr als einmal verwenden muss, den Prozess modularisieren muss. Nachdem ich einen weiteren Blick auf mein Problem geworfen habe, denke ich, dass es die richtige Entscheidung war, die Funktion loszuwerden. Vielen Dank. – Jake

+0

Ihre Regex funktioniert nicht mit einem NULL-Listenelement, sondern gibt den falschen Wert zurück.Versuchen Sie dies, wo das 3. Element von "listC" erwartet wird und das 2. Element ist NULL: 'mit tbl (col1) als ( wählen Sie 'listA ,, listC, listD' von Dual ) wählen Sie REGEXP_SUBSTR (col1, '[[] : alpha:]] + ', 1, 3) aus tbl; ' –

+0

Also würden Sie lieber die Regex einmal in Ihrer Funktion oder mehrere Male, überall in Ihrem Code beheben? Bleib bei deinem ursprünglichen Instinkt! –

0

Betrachten Sie diese Funktion:

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; 

Wie in diesem Beitrag nicht gefunden:

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

Bitte beachten Sie, dass Thread für eine Diskussion, die einige Informationen für Sie zur Verfügung stellen können.

+0

Für Sub-Strings ist dieser reguläre Ausdruck in Ordnung, aber er wird nicht verwendet, um die Anzahl der Elemente zu zählen: 'SELECT REGEXP_COUNT ('1,2,3', '(. *?) (\, | $)') FROM DUAL; 'Es zählt zu viel, aber nicht immer:' SELECT REGEXP_COUNT ('1,2,3,', '(. *?) (\, | $)') VON DUAL; ' – MT0

+0

@ MT0 Großartige Beobachtung! Zum Zählen von Elementen verwende ich normalerweise 'REGEXP_COUNT (' 1,2 ',', ') + 1' (zähle die Begrenzer und füge 1 hinzu). –

Verwandte Themen