2008-09-19 8 views
42

Je veux créer une procédure stockée avec un argument qui retournera différents ensembles d'enregistrements en fonction de l'argument. Quelle est la façon de faire cela? Puis-je l'appeler à partir de SQL simple?Comment renvoyer plusieurs lignes de la procédure stockée? (Oracle PL/SQL)

+0

probablement avec l'utilisation des fonctions de table. Jetez un oeil à cette documentation [Fonctions de table et expressions de curseur] (http://www.oreillynet.com/pub/a/network/2003/01/22/feuerstein.html) – Rene

Répondre

22

Je pense que vous voulez retourner un refcursor:

create function test_cursor 
      return sys_refcursor 
      is 
        c_result sys_refcursor; 
      begin 
        open c_result for 
        select * from dual; 
        return c_result; 
      end; 

Mise à jour: Si vous avez besoin d'appeler cela de SQL, utilisez une fonction de table comme @Tony Andrews suggéré.

+1

Je voudrais utiliser quelque chose comme ça , puisque je ne connais pas mes champs à l'avance. Mais 'select * from test_cursor' donne" tente d'accéder aux lignes d'un élément dont le type n'est pas connu ... " –

63

Voici comment construire une fonction qui renvoie un jeu de résultats qui peut être interrogé comme si elle était une table:

SQL> create type emp_obj is object (empno number, ename varchar2(10)); 
    2/

Type created. 

SQL> create type emp_tab is table of emp_obj; 
    2/

Type created. 

SQL> create or replace function all_emps return emp_tab 
    2 is 
    3  l_emp_tab emp_tab := emp_tab(); 
    4  n integer := 0; 
    5 begin 
    6  for r in (select empno, ename from emp) 
    7  loop 
    8  l_emp_tab.extend; 
    9  n := n + 1; 
10  l_emp_tab(n) := emp_obj(r.empno, r.ename); 
11  end loop; 
12  return l_emp_tab; 
13 end; 
14/

Function created. 

SQL> select * from table (all_emps); 

    EMPNO ENAME 
---------- ---------- 
     7369 SMITH 
     7499 ALLEN 
     7521 WARD 
     7566 JONES 
     7654 MARTIN 
     7698 BLAKE 
     7782 CLARK 
     7788 SCOTT 
     7839 KING 
     7844 TURNER 
     7902 FORD 
     7934 MILLER 
+2

Je pense que cela nécessite 10g, mais c'est la solution la plus élégante. (Je déteste les curseurs de référence). –

+0

Ce n'est pas une solution élégante parce que vous devez créer des types pour toutes les tables avec des colonnes différentes – zygimantus

3

Si vous voulez l'utiliser en SQL, je laisserais la procédure de sauvegarde remplissez une table ou une table temporaire avec les lignes résultantes (ou optez pour l'approche @Tony Andrews).
Si vous souhaitez utiliser la solution @ Thilo, vous devez placer le curseur en boucle à l'aide de PL/SQL. Voici un exemple: (j'ai utilisé une procédure au lieu d'une fonction, comme @Thilo a)

create or replace procedure myprocedure(retval in out sys_refcursor) is 
begin 
    open retval for 
    select TABLE_NAME from user_tables; 
end myprocedure; 

declare 
    myrefcur sys_refcursor; 
    tablename user_tables.TABLE_NAME%type; 
begin 
    myprocedure(myrefcur); 
    loop 
    fetch myrefcur into tablename; 
    exit when myrefcur%notfound; 
    dbms_output.put_line(tablename); 
    end loop; 
    close myrefcur; 
end; 
+0

Le point-virgule après 'notfound' a été ajouté selon un commentaire (posté comme réponse) par [Daniel] (http://stackoverflow.com/users/412349/daniel). –

8

Vous pouvez utiliser les fonctions Oracle pipeliné

En fait, quand vous voulez un PLSQL (ou java ou c) routine à la «source» de données - au lieu d'une table - vous utiliseriez une fonction pipelined.

Exemple simple - Génération Certaines données aléatoires
Comment pourriez-vous créer des nombres aléatoires N uniques en fonction de l'argument d'entrée?

create type array 
as table of number; 


create function gen_numbers(n in number default null) 
return array 
PIPELINED 
as 
begin 
    for i in 1 .. nvl(n,999999999) 
    loop 
    pipe row(i); 
end loop; 
return; 
end; 

Supposons que nous avions besoin de trois lignes pour quelque chose. Nous pouvons maintenant faire dans l'une des deux façons:

select * from TABLE(gen_numbers(3)); 

COLUMN_VALUE


 1 
     2 
     3 

ou

select * from TABLE(gen_numbers) 
where rownum <= 3; 

COLUMN_VALUE


 1 
     2 
     3 

pipelied Functions1 pipelied Functions2

+0

+1 Je pense que dans la plupart des cas, c'est la solution appropriée. Contrairement à la solution de Tony Andrews, il ne crée pas toutes les lignes à l'avance et nécessite moins de mémoire. – miracle173

+0

J'ai augmenté les votes de 1 à 2 et l'upvote est affiché dans mon navigateur – miracle173

+0

Merci pal. Merci. –

0
create procedure <procedure_name>(p_cur out sys_refcursor) as begin open p_cur for select * from <table_name> end; 
Questions connexes