Oracle:从记录数据类型中选择

Posted

技术标签:

【中文标题】Oracle:从记录数据类型中选择【英文标题】:Oracle: Select From Record Datatype 【发布时间】: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

【问题讨论】:

【参考方案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#

【讨论】:

以上是关于Oracle:从记录数据类型中选择的主要内容,如果未能解决你的问题,请参考以下文章

从访问 ORACLE 中插入选择

如何获取 blob 类型的数据以在 oracle 中插入?

从 Dual 中选择时是不是可以指定 Oracle 8i 伪列的数据类型

Toad 问题:Oracle 类型作为显示所有记录的表中列的数据类型

当嵌套表属于记录类型时,如何将数据填充到 Oracle 中的嵌套表中

Oracle 日期数据类型与 sysdate