2

传递参数时执行此代码块时出现问题。参数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一个字符串本身被执行。

有没有办法实现它?

4

4 回答 4

5

您可以分解字符串,或者最简单的方法是使用 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;
于 2012-07-03T12:34:06.773 回答
1

你可以做:

  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 不够了解……我认为 + 符号必须是 ||,但我认为您明白了。

于 2012-07-03T12:38:15.430 回答
1

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

于 2012-07-03T12:40:44.027 回答
1

您可以拆分输入字符串并使用临时表或表对象。这将允许优化器在您的列上使用索引。不要使用没有绑定的动态 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;
/
于 2012-07-03T13:20:49.970 回答