2016-06-08 2 views
0

Я хочу создать функцию, которая возвращает несколько столбцов 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 

Я должен создать функцию в пакете и внутреннее соединение результат как часть запроса.

+0

Что вызывает вызов этой функции с возвращенными данными? Кажется, вы хотите вернуть либо коллекцию, либо курсор, но который зависит от того, как она будет использоваться. (Для этого вам не нужен динамический SQL, но это отдельная проблема. Также полезно показать *, какую * ошибку вы получите, хотя это очевидно здесь.) –

+0

Почему вы «должны» сделать это так? Внутреннее присоединение к результату функции - одна из худших вещей, которую вы можете сделать. –

ответ

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) 
+0

Thx so much. Я попробовал sub-запрос. это работа, D – nettoon493

+0

всегда стараются сначала решить такие проблемы в SQL. Только если это не работает или усложняется, выполните функцию. Использование чистого SQL (в большинстве случаев) намного быстрее. –

1

Ошибка этот код бросает на «ORA-01006: переменная привязки не существует», потому что ваш execute immediate есть пункт using но запрос с использованием каскадных значений вместо привязки переменные. Конечно, лучше использовать привязки; вы немного усложняете ситуацию, меняя запрос условно. Но без этого все равно будет ошибка, поскольку вы пытаетесь выбрать три значения в одну строку, которая не будет идти.

Если вы хотите использовать результаты этого в другом запросе, вам необходимо вернуть коллекцию, и (из ссылки на внутреннее соединение) это должен быть тип коллекции на уровне схемы 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 является недействительным и решить, какой полный 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 являются нулевыми, что может быть более очевидным способом проверить, является ли это intenstion.

Вы можете видеть, что это находит, назвав его непосредственно:

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

.. и может использовать то же выражение коллекции таблицы, с псевдонимом таблицы, чтобы присоединиться к другим таблицам.

В зависимости от объема данных, вы можете захотеть сделать его конвейерной функцией. Может быть проще и эффективнее просто включать логику и эту таблицу в ваш большой запрос как встроенный просмотр или CTE.

+0

это ошибка: введите fnc_list_tab как таблицу fnc_list_obj PL-00103 .. "TABLE" ... – nettoon493

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; 
Смежные вопросы