你可以写一个函数:
CREATE FUNCTION parse_filters
RETURN CLOB
IS
v_sql CLOB := EMPTY_CLOB();
v_expr CLOB;
c_in_value_pattern VARCHAR2(60)
:= '('
|| '\d+\.\d*|\.\d+' -- Number literal
|| '|'
|| '''([^'']|'''')*''' -- String literal
|| '|'
|| '".*?"' -- Quoted identifier
|| '|'
|| '[A-Z][A-Z0-9_$#]*' -- Identifier
|| '),?';
PROCEDURE append_expr(
p_sql IN OUT CLOB,
p_expr IN CLOB,
p_oper IN VARCHAR2,
p_wrap IN BOOLEAN DEFAULT FALSE
)
IS
v_is_start CONSTANT BOOLEAN := LENGTH(p_sql) = 0;
BEGIN
IF NOT v_is_start THEN
p_sql := p_sql || ' ';
END IF;
IF NOT v_is_start THEN
p_sql := p_sql || p_oper || ' ';
END IF;
IF p_wrap THEN
p_sql := p_sql || '(' || p_expr || ')';
ELSE
p_sql := p_sql || p_expr;
END IF;
END;
BEGIN
FOR f IN (SELECT attribute, operator, value FROM filters)
LOOP
IF f.operator IN ('=', '<>', '!=') THEN
v_expr := EMPTY_CLOB() || f.attribute || ' ' || f.operator || ' ' || f.value;
append_expr(v_sql, v_expr, 'AND');
ELSIF LOWER(f.operator) = 'in' THEN
DECLARE
v_list FILTERS.VALUE%TYPE := SUBSTR(f.value, 2, LENGTH(f.value) - 2);
v_term FILTERS.VALUE%TYPE;
v_idx PLS_INTEGER := 1;
v_temp CLOB;
BEGIN
v_expr := EMPTY_CLOB();
LOOP
v_term := REGEXP_SUBSTR(f.value, c_in_value_pattern, 1, v_idx, 'i', 1);
EXIT WHEN v_term IS NULL;
v_temp := EMPTY_CLOB() || f.attribute || ' = ' || v_term;
append_expr(v_expr, v_temp, 'OR');
v_idx := v_idx + 1;
END LOOP;
append_expr(v_sql, v_expr, 'AND', TRUE);
END;
ELSIF LOWER(f.operator) = 'not in' THEN
DECLARE
v_list FILTERS.VALUE%TYPE := SUBSTR(f.value, 2, LENGTH(f.value) - 2);
v_term FILTERS.VALUE%TYPE;
v_idx PLS_INTEGER := 1;
BEGIN
LOOP
v_term := REGEXP_SUBSTR(f.value, c_in_value_pattern, 1, v_idx, 'i', 1);
EXIT WHEN v_term IS NULL;
v_expr := EMPTY_CLOB() || f.attribute || ' <> ' || v_term;
append_expr(v_sql, v_expr, 'AND');
v_idx := v_idx + 1;
END LOOP;
END;
END IF;
END LOOP;
RETURN v_sql;
END parse_filters;
/
对于您的示例数据:
CREATE TABLE filters ( Attribute, operator, value ) AS
SELECT 'col1', '=', '''02''' FROM DUAL UNION ALL
SELECT 'col2', 'In', '(''001'',''002'')' FROM DUAL UNION ALL
SELECT 'col3', '<>', '''A''' FROM DUAL UNION ALL
SELECT 'col4', 'Not In', '(''test1'',''test2'',''test3'')' FROM DUAL;
然后:
SELECT parse_filters() FROM DUAL;
输出:
| PARSE_FILTERS() |
| col1 = '02' AND (col2 = '001' OR col2 = '002') AND col3 <> 'A' AND col4 <> 'test1' AND col4 <> 'test2' AND col4 <> 'test3' |
db小提琴here