Oracle PL/SQL函数中如何使用变量
How to use variables in Oracle PL/SQL Function
我很抱歉,因为这个问题似乎很简单。
我有这个功能:
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;
但是我收到错误消息:
Error(13,30): PL/SQL: ORA-00920: invalid relational operator
我连编译都不会。如果我使用 Viewname 和 Where_clause 的确切值,我会得到想要的结果。
我做错了什么?
/编辑:第 13 行是
from VIEWNAME
/编辑#2:
谢谢你们。你帮了我很多。我在第一步中没有考虑动态 sql,所以感谢复习 ;)。
你会想要使用 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;
我建议您在添加 EXECUTE IMMEDIATE
的同时添加 EXCEPTION BLOCK
我创建了一个 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
这是 PL/SQL 中最直接的静态 SQL 解决方案需要重复代码的领域之一,因为无法在查询中参数化 table 名称。就我个人而言,我通常更喜欢静态 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;
我很抱歉,因为这个问题似乎很简单。 我有这个功能:
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;
但是我收到错误消息:
Error(13,30): PL/SQL: ORA-00920: invalid relational operator
我连编译都不会。如果我使用 Viewname 和 Where_clause 的确切值,我会得到想要的结果。
我做错了什么?
/编辑:第 13 行是
from VIEWNAME
/编辑#2: 谢谢你们。你帮了我很多。我在第一步中没有考虑动态 sql,所以感谢复习 ;)。
你会想要使用 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;
我建议您在添加 EXECUTE IMMEDIATE
的同时添加 EXCEPTION BLOCK
我创建了一个 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
这是 PL/SQL 中最直接的静态 SQL 解决方案需要重复代码的领域之一,因为无法在查询中参数化 table 名称。就我个人而言,我通常更喜欢静态 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;