如何在Oracle PL / SQL函数中使用变量

时间:2015-08-07 13:58:25

标签: oracle plsql stored-functions

我很抱歉,因为这个问题似乎很容易。 我有这个功能:

CREATE OR REPLACE FUNCTION Costs_MK (VIEWNAME IN VARCHAR2 , WHERE_CLAUSE IN VARCHAR2) 
RETURN VARCHAR2

IS
   v_Costs VARCHAR2 (500);

BEGIN

  Select Listagg(Costs, ';' ) WITHIN GROUP (ORDER BY Costs)
  into v_Costs
  from (select distinct (Costs) 
        from VIEWNAME
        where WHERE_CLAUSE);

  RETURN v_Costs;
END Costs_MK;

但是我收到了错误消息:

  

错误(13,30):PL / SQL:ORA-00920:无效的关系运算符

我甚至无法编译它。如果我使用Viewname和Where_clause的确切值,我会得到所需的结果。

我做错了什么?

/ edit:第13行是

from VIEWNAME

/编辑#2: 多谢你们。你帮助了我很多。我没有在第一步中考虑动态sql,所以感谢复习;)。

3 个答案:

答案 0 :(得分:1)

我建议您添加EXCEPTION BLOCK以及EXECUTE IMMEDIATE 我创建了一个PROCEDURE您可以类似地创建FUNCTION

CREATE OR REPLACE procedure Costs_PK(VIEWNAME IN VARCHAR2 , WHERE_CLAUSE IN VARCHAR2 ) 
  AS
v_Costs VARCHAR2 (500);
sql_stmnt varchar2(2000);
BEGIN
sql_stmnt := 'Select Listagg(Cost, '';'' ) WITHIN GROUP (ORDER BY Cost) from (select distinct (Cost) from ' || VIEWNAME || ' where ' || WHERE_CLAUSE || ' ) ';
--sql_stmnt := 'Select Listagg(Cost, '';'' ) WITHIN GROUP (ORDER BY Cost) from (select distinct (Cost) from cost_tab where cost >=123 ) ';
EXECUTE IMMEDIATE sql_stmnt INTO v_Costs ;
dbms_output.put_line ('query   works  -- ' || v_costs);
EXCEPTION
WHEN OTHERS  THEN 
DBMS_OUTPUT.PUT_LINE ('input :' || VIEWNAME || ' and  ' || WHERE_CLAUSE );
dbms_output.put_line (sql_stmnt );
DBMS_OUTPUT.PUT_LINE ('ERROR MESSAGE : ' || sqlCODE || ' ' || SQLERRM );
END;

begin
Costs_PK('cost_tab','cost >= 123');
end;

NOTE:代码已经过测试

<强>输出:

query   works  -- 123;456

TESTED

答案 1 :(得分:1)

这是PL / SQL中的一个领域,其中最简单的静态SQL解决方案需要代码重复,因为无法在查询中参数化表名。就个人而言,我通常喜欢重复的静态SQL代码而不是动态SQL的复杂性,因为我喜欢PL / SQL编译器来检查我的SQL编译时间。 YMMV。

您没有告诉我们不同观点的where陈述类型。在下面的示例中,我假设视图与where参数之间存在1:1的关系,因此我可以轻松构建静态SQL。

create or replace view foo_v (foo_id, cost) as
select level, level*10 from dual connect by level < 10
;

create or replace view bar_v (bar_id, cost) as
select level, level*100 from dual connect by level < 10
;

create or replace function cost_mk(
  p_view in varchar2
 ,p_foo_id in number default null
 ,p_bar_id in number default null
) return varchar2 is
  v_cost varchar2(32767);
begin
  case lower(p_view)
    when 'foo_v' then
      select listagg(cost, ';' ) within group (order by cost)
        into v_cost
        from (select distinct cost
                from foo_v
               where foo_id < p_foo_id);
    when 'bar_v' then
      select listagg(cost, ';' ) within group (order by cost)
        into v_cost
        from (select distinct cost
                from bar_v
               where bar_id < p_bar_id);
  end case;

  return v_cost;
end;
/
show errors

使用示例

select cost_mk(p_view => 'foo_v', p_foo_id => 5) from dual;
select cost_mk(p_view => 'bar_v', p_bar_id => 5) from dual;

答案 2 :(得分:-3)

您可能希望使用EXECUTE IMMEDIATE,如您对问题的评论所暗示的那样,定义一个新变量sqlQuery VARCHAR2(200);或类似的内容并重新编写您的sql,类似于以下内容:

sqlQuery := 'Select Listagg(Costs, '';'' ) WITHIN GROUP (ORDER BY Costs) ';
sqlQuery := sqlQuery || 'from (select distinct (Costs) from :1 where :2)';
EXECUTE IMMEDIATE sqlQuery INTO v_Costs USING VIEWNAME, WHERE_CLAUSE;