【问题标题】:Oracle query to divide rows into delimiterOracle查询将行划分为分隔符
【发布时间】:2022-01-10 10:18:29
【问题描述】:

我有如下数据。

Attribute operator value
col1 = 02
col2 In ('001','002')
col3 <> A
col4 Not In ('test1','test2','test3')

我正在尝试将其转换为以下格式。

col1=02 AND col2=001 OR col2=002 AND col3<>A AND col4<>test1 AND col4<>test2 AND col4<>test3

您能否建议 oracle SELECT 查询。

提前致谢。

【问题讨论】:

  • 该输出格式错误,因为AND 的优先级高于OR。您的预期输出表示(col1=02 AND col2=001) OR (col2=002 AND col3&lt;&gt;A AND col4&lt;&gt;test1 AND col4&lt;&gt;test2 AND col4&lt;&gt;test3),而它应该表示col1=02 AND (col2=001 OR col2=002) AND col3&lt;&gt;A AND col4&lt;&gt;test1 AND col4&lt;&gt;test2 AND col4&lt;&gt;test3
  • IN 工作正常。将其更改为OR 系列似乎毫无意义。而且col1&lt;&gt;test1col1 in ('test1') 不一样

标签: sql oracle


【解决方案1】:

如果您想检查 Oracle 如何解释谓词,只需使用包含您的谓词的 WHEREclause 创建查询。

具有对应列的表必须存在但可能为空。

然后调用explain plan 并查看结果 - 检查谓词信息中的filter

EXPLAIN PLAN  SET STATEMENT_ID = 'jara1' into   plan_table  FOR
select * from tab
where 
col1 = 02 and
col2 in ('001','002') and
col3 <> 'A' and
col4 not in ('test1','test2','test3');

得到结果(为简洁起见)

SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));

...
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("COL1"=02 AND ("COL2"='001' OR "COL2"='002') AND 
              "COL3"<>'A' AND "COL4"<>'test1' AND "COL4"<>'test2' AND "COL4"<>'test3')

【讨论】:

    【解决方案2】:

    你可以写一个函数:

    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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      • 1970-01-01
      • 2014-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多