【问题标题】:How to use variables in Oracle PL/SQL Function如何在 Oracle PL/SQL 函数中使用变量
【发布时间】:2015-08-07 13:58:25
【问题描述】:

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

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,所以感谢你的复习;)。

【问题讨论】:

  • from VIEWNAME 你不能在这里使用变量......你需要使用动态 SQL ......这立即引出了一个更大的问题:“你想做什么?” .. 因为为这样的事情诉诸动态 SQL 通常可能是设计不佳的标志 .. ;) (并非总是 .. 但经常)
  • where WHERE_CLAUSE 如果没有动态 SQL,这也不会像这样工作......(见上文)
  • 谢谢。我正在尝试在我的过程中使用返回值。我在运行时在我的过程中获得了 Viewname,我想用 viewname 调用该函数,然后得到我的返回值。否则我将不得不编写 5 个函数来获取值。与“where WHERE_CLAUSE”相同的问题。有什么解决方案的建议吗?这么动态的SQL?
  • 我可能会使用 5 个函数 .. 每个视图 1 个 ... 但这只是我 .. :) 其他人可能不同意。
  • where 子句有多“动态”?视图总是一样的吗?

标签: oracle plsql stored-functions


【解决方案1】:

我建议您添加EXCEPTION BLOCKEXECUTE 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

【讨论】:

    【解决方案2】:

    这是 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;
    

    【讨论】:

      【解决方案3】:

      您可能希望使用 cmets 对您的问题所暗示的 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;
      

      【讨论】:

      • 您不能将绑定变量用于视图名称或动态where 子句。您只能将绑定变量用于 where costs &gt; :1 等变量值。
      猜你喜欢
      • 2017-03-29
      • 2013-08-30
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多