函数如何返回多列?

时间:2016-06-08 11:45:11

标签: oracle stored-procedures plsql

我想创建一个返回多个varchar2列的函数。他是我到目前为止所做的,但在execute immediate电话中出错了。

FUNCTION FNC_LST_OUR(p_com_code   varchar2,
                     p_from  varchar2,
                     p_to    varchar2                                  
                     ) return VARCHAR2 is                                 

v_sql VARCHAR2(30000) := '';
v_sql2 VARCHAR2(30000) := '';  
error_msg_tmp varchar2(255);

begin  
      v_sql := 'select s.com_code, s.p_code, count(*) as Num_SIMRP    
                from p_stest s                 
                where s.com_code = ''' || p_com_code || '''                                      
                and s.s_status = ''ACTIVE''
                and s.s_type like ''H%'' ';                 
      if p_from is not null then
        v_sql := v_sql || ' and s.p_code between ''' || p_from || ''' and ''' || p_to || '''';
      end if;          
        v_sql := v_sql || ' group by s.com_code,s.p_code
                            having count(s.p_code)> 0 ';

      EXECUTE IMMEDIATE v_sql INTO v_sql2 USING p_com_code; --> Error This Line
      return v_sql2;
end;     

我需要它来返回多个列,如:

com_code | p_code | num_simrp
A        | ADSWQ  | 14
A        | AQWSA  | 8
A        | DEWSQ  | 10
A        | SDERS  | 45
A        | DFDEW  | 80

我必须在包中创建函数,并将结果内部连接作为查询的一部分。

3 个答案:

答案 0 :(得分:1)

此代码抛出的错误是" ORA-01006:绑定变量不存在",因为您的execute immediateusing子句但查询使用的是连接值而不是绑定变量。当然,使用绑定会更好;通过有条件地更改查询,您会使事情变得复杂。但是如果没有它,它仍然会出错,因为你试图在一个字符串中选择三个值,而这些字符串是不会的。

如果要在另一个查询中使用this的结果,则需要返回一个集合,并且(从内部联接引用)它需要是一个SQL模式级集合类型而不是PL / SQL集合类型

create type fnc_list_obj as object (
  com_code varchar2(10),
  p_code varchar2(10),
  num_simrp number)
/

create type fnc_list_tab as table of fnc_list_obj
/

create package p42 as
function FNC_LST_OUR(P_COM_CODE   varchar2,
                     p_from  varchar2,
                     p_to    varchar2                                  
                     ) return fnc_list_tab;
end p42;
/

您不需要使用动态SQL。您可以检查p_from是否为null并确定要运行哪个完整的SQL查询,或者更简单地在单个查询中包含该检查:

create package body p42 as
function fnc_lst_our(p_com_code varchar2,
                     p_from varchar2,
                     p_to varchar2
                     ) return fnc_list_tab is

      v_fnc_list fnc_list_tab;
begin
      select fnc_list_obj(s.com_code, s.p_code, count(*))
      bulk collect into v_fnc_list
      from p_stest s
      where s.com_code = p_com_code
      and s.s_status = 'ACTIVE'
      and s.s_type like 'H%'
      and (p_from is null or s.p_code between p_from and p_to)
      group by s.com_code,s.p_code
      having count(s.p_code)> 0;

      return v_fnc_list;
end;
end p42;
/

having子句可能是多余的,但目前它排除了所有p_code值为空的行,这可能是一种更明显的方法来检查这是否是强度

您可以通过直接调用它来查看找到的内容:

select * from table(p42.fnc_lst_our('A', null, null));

..并且可以使用带有表别名的相同表集合表达式来连接到其他表。

取决于您可能希望使其成为流水线函数的数据量。将逻辑和该表作为内联视图或CTE包含在更大的查询中可能更简单,更有效。

答案 1 :(得分:0)

忘记整个函数,你可以使用子查询。我想你想要这样的东西:

select *
from a_table a
join (select s.com_code, s.p_code, count(*) as Num_SIMRP    
      from p_stest s                 
      where s.s_status = 'ACTIVE'
        and s.s_type like 'H%'
      group by s.com_code,s.p_code
      having count(s.p_code) > 0) b on b.com_code = a.com_code 
                                    and (p_from is null or s.p_code between p_from and p_to)

答案 2 :(得分:0)

create or replace type  test_type as object(t_owner varchar2(2000),t_originator varchar2(2000),
t_modify_dat timestamp,t_create_date  timestamp);

create or replace type  test_table is table of test_type;

create or replace function test_fn(table_name varchar2)
return test_table
as
test_var test_table:=test_table();
t_owner varchar2(2000);
t_originator varchar2(2000);
t_modify_date timestamp;
t_create_date timestamp;
begin

      execute immediate 'select  "OWNER","ORIGINATOR","MODIFIED","ORIGINATED"   from '|| table_name ||'
           where  revision = 1 and "TYPE" like ''gecPowder'' and "NAME" like ''GE2009-0653'''
           into t_owner,t_originator,t_modify_date,t_create_date;
           test_var.extend();
           --DBMS_OUTPUT.PUT_line(t_owner||t_originator||t_modify_date||t_create_date);
           select test_type(t_owner,t_originator,t_modify_date,t_create_date) bulk collect into test_var from dual;
           return test_var;
           end;