【问题标题】:Passing multiple variables into WHERE condition in PL/SQL Stored Procedure在 PL/SQL 存储过程中将多个变量传递给 WHERE 条件
【发布时间】:2012-07-03 12:32:15
【问题描述】:

在传递参数时执行此代码块时出现问题。参数 rf 是要输入到 WHERE 子句中的变量列表。要输入的变量数量不是静态的。

create or replace
procedure test_pl(rf in varchar2)
IS 
counter number;

BEGIN
  select count(*) into counter from test_pl_imp where column_name in (rf);
  dbms_output.put_line(counter);
END;

执行代码如下:

declare 
inparam varchar2(20) := 'xyz,ran,dom';
begin
goku.test_pl(inparam);
end;
/

我希望 WHERE 条件像这样执行:

where column_name in ('xyz','ran','dom');

但它会在将xyz,ran,dom 本身视为字符串的情况下执行。

有什么方法可以实现吗?

【问题讨论】:

    标签: sql stored-procedures plsql


    【解决方案1】:

    您可以分解字符串,或者最简单的方法是使用 INSTR。

    rf := ',' || rf || ',';
    
    SELECT
        COUNT(*)
    INTO
        counter
    FROM
        test_pl_imp
    WHERE
        INSTR(rf, ',' || column_name || ',') > 0;
    

    如果您可以选择稍微重新设计它,我认为采用字符串数组并将其转换为 TABLE 以便加入 test_pl_imp 会是一种更简洁的设计。

    这可以按如下方式完成:

    DECLARE
        l_array   goku.t_type := goku.t_type();
    BEGIN
        l_array.extend(3);
        l_array(1) := 'xzy';
        l_array(2) := 'abc';
        l_array(2) := '123';
    
        goku.test_pl(l_array);
    END;
    

    然后您的包规范将包括以下内容,因为您希望上述调用的类型和过程是公开的:

    CREATE OR REPLACE PACKAGE goku
        TYPE r_type IS RECORD (
            search_term    VARCHAR2 (30)
        );
    
        TYPE t_type IS TABLE OF r_type;
    
        PROCEDURE test_pl(l_array IN t_type);
    END goku;
    

    您的包裹体将类似于以下内容:

    CREATE OR REPLACE PACKAGE BODY goku
        PROCEDURE test_pl(l_array IN t_type) IS
            v_counter NUMBER;
        BEGIN
    
            SELECT
                COUNT(tpi.*)
            INTO
                v_counter
            FROM
                test_pl_imp tpi
                , TABLE( CAST(l_array as r_type)) la
            WHERE
                tpi.column_name = la.search_term;
    
            DBMS_OUTPUT.PUT_LINE('Count :' || v_counter);
        END;
    END goku;
    

    【讨论】:

    • INSTR 在仅提供“MyString”作为变量时可能会遇到“MyString”和“MyStringTest”等问题。但要绕过它,您可以用特殊字符和变量填充原始值,以便它会查找“;MyString;”反而。我以前也做过这个技巧。
    • 关闭... 您还需要为列表中的第一个值填充开头。无论如何+1。干得好!
    • 啊,你又是对的——我忘了​​如果你只搜索 yz 会发生什么。
    • @Chris .. 非常感谢您的帮助!非常好的“技巧”要记住。像奇迹一样工作!
    • 只是一个疑问:你能告诉我如何在 WHERE 子句 pl/sql 中使用可变长度的 array 吗?
    【解决方案2】:

    您将参数声明为单个字符串(varchar),然后它将被视为唯一字符串。 可以尝试拆分参数:http://www.codeproject.com/Articles/7938/SQL-User-Defined-Function-to-Parse-a-Delimited-Str

    【讨论】:

      【解决方案3】:

      你可以这样做:

      1. 将存储的 proc 查询转换为动态查询,并将值作为 '''abc''、''etc''' 传递
      2. 实现拆分函数将字符串拆分为临时表并对其进行连接/查询。
      3. 您可以使用 INSTR,但有一个技巧。

      我在我工作的地方编写了一个拆分函数,它非常适合这样的事情。


      INSTR 技巧:您当前将逗号作为分隔符传递,这就是我在“技巧”中使用的,但您也可以使用分号。基本上,假设您想在 'abc,def' 中查找所有内容。您填充字符串以使其看起来像',abc,def',然后填充正在搜索的值,使其看起来像',abc,'。这样,'abctest' 和 'testabc' 没有找到,而 'abc' 找到了。

      SELECT 
          COUNT(*) 
      INTO 
          counter 
      FROM 
          test_pl_imp 
      WHERE 
          INSTR(',' + rf + ',', ',' + column_name + ',') > 0;
      

      对不起,如果我对 PL/SQL 不够了解...我认为 + 符号应该是 ||,但我想你明白了。

      【讨论】:

        【解决方案4】:

        您可以拆分输入字符串并使用临时表或表对象。这将允许优化器在您的列上使用索引。不要使用没有绑定的动态 SQL(出于安全和性能原因)。

        这是一个带有表格对象的示例。设置(10g,因为它使用REGEXP_SUBSTR):

        CREATE TYPE tab_varchar2 IS TABLE OF VARCHAR2(100);-- longest string
        /
        CREATE OR REPLACE PROCEDURE test_pl(rf IN VARCHAR2) IS
           lt tab_varchar2;
           counter NUMBER;
        BEGIN
           -- split parameter
           SELECT rtrim(regexp_substr(str, '[^,]*,', 1, level), ',')
             BULK COLLECT INTO lt
             FROM (SELECT rf || ',' str FROM dual)
          CONNECT BY level <= length(str) - length(replace(str, ',', ''));
           -- your query
           SELECT count(*)
             INTO counter
             FROM test_pl_imp
            WHERE column_name IN (SELECT column_value FROM TABLE(lt));
           dbms_output.put_line(counter);
        END;
        /
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-10-06
          • 1970-01-01
          • 1970-01-01
          • 2015-12-20
          • 2011-09-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多