2009-06-19 2 views
4

J'ai une fonction qui renvoie un type de données d'enregistrement (2 champs: ID et nom). Comment puis-je obtenir les données d'une déclaration select? En particulier, j'essaye d'utiliser un objet OracleCommand essayant d'obtenir l'objet dans mon code C#. J'ai d'abord essayé ...Oracle: Sélectionner à partir de l'enregistrement Type de données

CALL FUNCTION_NAME() INTO :loRetVal 

... mais j'obtiens une erreur de type de données pour le type que j'utilise. J'ai aussi essayé ...

SELECT * FROM FUNCTION_NAME() 

... et ...

SELECT * FROM TABLE (FUNCTION_NAME()) 

... en vain. Je suppose que je cherche ...

SELECT * FROM RECORD (FUNCTION_NAME()) 

... qui, bien sûr, n'existe pas.

La seule solution que j'ai été capable de proposer est d'enrouler cet appel de fonction dans un autre appel de fonction dans lequel la fonction externe retourne un TABLE d'enregistrements contenant cet enregistrement unique. Ceci, cependant, semble lourd et je cherche une méthode plus simple. Toute aide serait appréciée.

EDIT: Désolé, j'ai également essayé SELECT FUNCTION_NAME() FROM DUAL.

Répondre

2

Je pense que ce que vous cherchez; pour obtenir les valeurs dans une instruction select:

select result.id as id, result.name 
    from (select function() as result from dual); 

Parce que votre fonction retourne un enregistrement d'un pas un type natif, vous ne pouvez pas utiliser les méthodes standard. Si vous souhaitez obtenir l'enregistrement réel en tant qu'objet dans C#, vous devez lire les types définis par l'utilisateur dans la documentation ODP .net.

Vous pouvez également placer la fonction dans une autre fonction qui renvoie un curseur de référence et qui est utilisée en C# de façon plus standard.

6

Un type de données d'enregistrement est un type de données PL/SQL. SQL ne le sait pas. C'est probablement pourquoi vous obtenez une erreur. Voir cet exemple:

SQL> create package mypkg 
    2 as 
    3 type myrec is record 
    4 (id int 
    5 , name varchar2(10) 
    6 ); 
    7 function f return myrec; 
    8 end mypkg; 
    9/

Package created. 

SQL> create package body mypkg 
    2 as 
    3 function f return myrec 
    4 is 
    5  r myrec; 
    6 begin 
    7  r.id := 1; 
    8  r.name := 'test'; 
    9  return r; 
10 end f; 
11 end mypkg; 
12/

Package body created. 

SQL> desc mypkg 
FUNCTION F RETURNS RECORD 
    ID       NUMBER(38)    OUT 
    NAME       VARCHAR2(10)   OUT 

SQL> select mypkg.f from dual 
    2/
select mypkg.f from dual 
     * 
ERROR at line 1: 
ORA-00902: invalid datatype 

L'erreur dans SQL I faisait référence à. Vous pouvez l'appeler de PL/SQL si:

SQL> declare 
    2 r mypkg.myrec; 
    3 begin 
    4 r := mypkg.f; 
    5 dbms_output.put_line(r.id); 
    6 dbms_output.put_line(r.name); 
    7 end; 
    8/
1 
test 

PL/SQL procedure successfully completed. 

Si vous souhaitez utiliser la fonction dans SQL, vous pouvez créer une objecttype SQL. Notez qu'appeler votre fonction directement à partir de C# est beaucoup plus préférable que d'insister sur l'utilisation de SQL pour cela. Mais juste pour le dossier:

SQL> drop package mypkg 
    2/

Package dropped. 

SQL> create type myobj is object 
    2 (id int 
    3 , name varchar2(10) 
    4 ); 
    5/

Type created. 

SQL> create package mypkg 
    2 as 
    3 function f return myobj; 
    4 end mypkg; 
    5/

Package created. 

SQL> create package body mypkg 
    2 as 
    3 function f return myobj 
    4 is 
    5 begin 
    6  return myobj(1,'test'); 
    7 end f; 
    8 end mypkg; 
    9/

Package body created. 

SQL> select mypkg.f from dual 
    2/

F(ID, NAME) 
-------------------------------------------------------------- 
MYOBJ(1, 'test') 

1 row selected. 

Cordialement, Rob .

+2

J'aime vraiment votre réponse. Pour continuer sur ce chemin. Vous pouvez créer une collection et la diffuser dans le SQL. - Créer un type de collection CREATE TYPE myobj_tab AS TABLE OF - que la fonction renvoie un type de collection CREATE OR REPLACE fonction f return myobj_tab IS objtab myobj_tab; commencer objtab: = myobj_tab (myobj (1, 'test')); return objtab; fin f; - METTEZ-le comme une table et sélectionnez-le directement. SELECT id, nom FROM TABLE (CAST (f() AS myobj_tab)); – David

1

Le format de mon commentaire pour Rob van Wijk est mauvais. Pour continuer sa pensée.

-- create a collection type 
CREATE TYPE myobj_tab AS TABLE OF myobj; 

-- have the function return a collection type 
CREATE OR REPLACE function f return myobj_tab 
IS 
    objtab myobj_tab; 
BEGIN 
    objtab := myobj_tab(myobj(1,'test')); 
    return objtab; 
end f; 

-- CAST it as a table and straight up select from it. 
SELECT id, name FROM TABLE(CAST(f() AS myobj_tab)); 
2

Pouvez-vous

CREATE TYPE <object name> AS TABLE OF <record type> 

et l'utiliser directement dans une instruction SQL? Je demande parce que j'ai un proc stocké que je ne peux pas éditer. Le proc stocké a une variable de sortie qui est le type d'enregistrement que je dois référencer dans une instruction SQL. J'ai déjà créé une fonction pour appeler le proc, mais si je n'ai pas besoin de convertir l'enregistrement pour taper l'objet ce serait sympa.

je plus tard appeler comme:

SELECT * 
FROM TABLE(CAST(<function name>() as <object name>)); 
1

Je pense que vous êtes à la recherche de fonctionnalités PIPELINE:

CREATE TABLE test_table(tt_id INTEGER,tt_text VARCHAR2(40)); 

CREATE PACKAGE test_pkg IS 
    TYPE tp_rec IS RECORD(tt_id INTEGER,tt_text VARCHAR2(40)); 
    TYPE tp_recs IS TABLE OF tp_rec; 

    FUNCTION test_func RETURN tp_recs PIPELINED; 
    FUNCTION test_func1 RETURN tp_recs PIPELINED; 
    FUNCTION test_func2(ivar INTEGER) RETURN tp_recs PIPELINED; 
END; 
/

CREATE OR REPLACE PACKAGE BODY test_pkg IS 
    FUNCTION test_func RETURN tp_recs PIPELINED 
    AS 
     currec tp_rec; 
    BEGIN 
     currec.tt_id := 1; 
     currec.tt_text := 'test1'; 
     PIPE ROW(currec); 
    END; 

    FUNCTION test_func1 RETURN tp_recs PIPELINED 
    AS 
     currec tp_rec; 
     CURSOR t_cursor IS 
      SELECT * FROM test_table; 
    BEGIN 
     OPEN t_cursor; 
     LOOP 
      FETCH t_cursor INTO currec; 
      EXIT WHEN t_cursor%NOTFOUND; 
      PIPE ROW(currec); 
     END LOOP; 
     CLOSE t_cursor; 
    END; 

    FUNCTION test_func2(ivar INTEGER) RETURN tp_recs PIPELINED 
    AS 
     currec tp_rec; 
    BEGIN 
     SELECT * INTO currec FROM test_table WHERE tt_id = ivar; 
     PIPE ROW(currec); 
    END; 

END; 
/

BEGIN 
    INSERT INTO test_table VALUES(1,'test1'); 
    INSERT INTO test_table VALUES(2,'test2'); 
    INSERT INTO test_table VALUES(3,'test3'); 
    COMMIT; 
END; 
/

SELECT * FROM TABLE(test_pkg.test_func()); 
SELECT * FROM TABLE(test_pkg.test_func1()); 
SELECT * FROM TABLE(test_pkg.test_func2(2)); 

Le code ci-dessus est testé, et devrait vous donner un bon départ à ce sujet. Il suffit de rechercher le mot-clé PIPELINED dans Oracle pour plus d'informations (en supposant que vous travaillez avec Oracle ...)

Questions connexes