【问题标题】:Oracle: Select From Record DatatypeOracle:从记录数据类型中选择
【发布时间】:2009-06-19 22:40:56
【问题描述】:

我有一个返回记录数据类型的函数(2 个字段:ID 和名称)。如何从 select 语句中获取数据?

具体来说,我正在尝试使用 OracleCommand 对象来尝试将该对象放入我的 C# 代码中。我最初尝试过...

CALL FUNCTION_NAME() INTO :loRetVal

...但无论我使用什么类型,我都会收到数据类型错误。我也试过...

SELECT * FROM FUNCTION_NAME()

...和...

SELECT * FROM TABLE ( FUNCTION_NAME() )

... 无济于事。我想我正在寻找...

SELECT * FROM RECORD ( FUNCTION_NAME() )

...当然不存在。

我能想出的唯一解决方案是将此函数调用包装在另一个函数调用中,其中外部函数返回包含该唯一记录的记录表。但是,这似乎很麻烦,我正在寻找一种更简单的方法。任何帮助将不胜感激。

编辑:对不起,我也试过SELECT FUNCTION_NAME() FROM DUAL

【问题讨论】:

    标签: oracle


    【解决方案1】:

    记录数据类型是 PL/SQL 数据类型。 SQL 对此一无所知。这可能就是您收到错误的原因。看这个例子:

    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
    

    我指的是 SQL 中的错误。 你可以从 PL/SQL 中调用它:

    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.
    

    如果你想在 SQL 中使用该函数,那么你可以创建一个 SQL 对象类型。请注意,直接从 C# 调用您的函数看起来比坚持使用 SQL 来执行此操作更可取。但仅作记录:

    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.
    

    问候, 抢。

    【讨论】:

    • 我真的很喜欢你的回答。继续走这条路。您可以创建一个集合并将其转换为 SQL。 -- 创建一个集合类型 CREATE TYPE myobj_tab AS TABLE OF myobj; -- 让函数返回一个集合类型 CREATE OR REPLACE 函数 f return myobj_tab IS objtab myobj_tab;开始 objtab := myobj_tab(myobj(1,'test'));返回对象表;结束 f; -- 将其投射为表格并从中直接选择。 SELECT id, name FROM TABLE(CAST(f() AS myobj_tab));
    【解决方案2】:

    我认为这就是您要寻找的;在 select 语句中获取值:

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

    因为您的函数返回的记录不是原生类型,所以您不能使用标准方法。如果您想将实际记录作为对象获取到 C# 中,那么您必须阅读 ODP .net 文档中的用户定义类型。

    您还可以将函数包装在另一个函数中,该函数返回一个引用光标,并且在 C# 中以更标准的方式使用。

    【讨论】:

      【解决方案3】:

      可以吗

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

      并直接在 SQL 语句中使用它?我问是因为我有一个无法编辑的存储过程。存储过程有一个输出变量,它是我必须在 SQL 语句中引用的记录类型。我已经创建了一个函数来调用 proc,但是如果我不必将记录转换为类型对象,那就太好了。

      我以后会这样称呼它:

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

      【讨论】:

        【解决方案4】:

        我对 Rob van Wijk 的评论格式不好。继续他的想法。

        -- 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));
        

        【讨论】:

          【解决方案5】:

          我认为您正在寻找 PIPELINED 功能:

          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));
          

          上面的代码已经过测试,应该会给你一个好的开始。只需在 Oracle 中查找 PIPELINED 关键字以获取更多信息(假设您正在使用 Oracle...)

          【讨论】:

            【解决方案6】:

            为什么需要使用 SQL?您也许可以只使用 System.Data.CommandType.StoredProcedure 来调用该函数。

            call-an-oracle-function-from-c#

            Call Oracle Function in package with C#

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-08-20
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-06-20
              • 2018-02-23
              • 1970-01-01
              相关资源
              最近更新 更多