我有一些我无法改变的表格。对于每个表,我需要在FUNCTION
内创建一个PACKAGE
,它返回一个与原始表具有相同数据/布局的临时表。我不想手动复制所有表列定义,而是使用%ROWTYPE
等语句。
我想告诉Oracle:“此函数返回一个与原始表格XY布局相同的表格。”
请看一下这个例子。这是(遗留)表:
CREATE TABLE TEST.Emp (
ID RAW(16),
NAME VARCHAR2(10)
);
/
这些是包和类型定义:
CREATE OR REPLACE TYPE TEST.row_Emp AS OBJECT (
ID RAW(16),
NAME VARCHAR2(10)
);
/
CREATE OR REPLACE PACKAGE TEST.Emp_PKG AS
TYPE t_Emp IS TABLE OF TEST.row_Emp INDEX BY BINARY_INTEGER;
FUNCTION F_Emp_Select (
VersionId INT DEFAULT NULL
) RETURN t_Emp;
END;
/
这是包体:
CREATE OR REPLACE PACKAGE BODY TEST.Emp_PKG AS
FUNCTION F_Emp_Select (
VersionId INT DEFAULT NULL
) RETURN t_Emp
AS
VersionVar INT := VersionId;
v_ret t_Emp;
BEGIN
SELECT
CAST(
MULTISET(
SELECT ID, NAME FROM TEST.Emp
) AS t_Emp) -- <== this is line 15
INTO v_ret
FROM dual;
RETURN v_ret;
END;
END;
/
如果我在SQLPlus中执行此操作,则会收到以下错误:
Errors for PACKAGE BODY TEST.EMP_PKG:
LINE/COL ERROR
-------- -----------------------------------------------------------------
11/9 PL/SQL: SQL Statement ignored
15/22 PL/SQL: ORA-00902: invalid datatype
我做错了什么?
编辑:我需要这个用于更复杂的案例。此功能将用于其他功能和程序。例如,我需要能够对函数的结果进行连接:
SELECT ... FROM ...
INNER JOIN TEST.Emp_PKG.F_Emp_Select(...) ON ...
所以我不需要整个结果。
很抱歉这个混乱,我来自SQL Server,我多次做过这样的事情。
答案 0 :(得分:3)
如果您需要将结果视为表格,则可以使用管道功能:</ p>
CREATE OR REPLACE TYPE row_Emp AS OBJECT (
ID RAW(16),
NAME VARCHAR2(10)
);
/
CREATE OR REPLACE TYPE tab_Emp AS TABLE OF row_Emp
/
CREATE OR REPLACE PACKAGE Emp_PKG AS
FUNCTION F_Emp_Select (
VersionId INT DEFAULT NULL
) RETURN tab_Emp PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY Emp_PKG AS
FUNCTION F_Emp_Select (
VersionId INT DEFAULT NULL
) RETURN tab_EMP PIPELINED
AS
BEGIN
FOR row IN (SELECT ID, NAME FROM Emp) LOOP
PIPE ROW (row_Emp(row.ID, row.NAME));
END LOOP;
RETURN;
END;
END;
/
请注意,必须在架构级别声明对象类型和表类型;表类型不能是PL / SQL-seclared表(集合)类型,因为它不能在纯SQL中使用,即使在其他PL / SQL中也是如此。遗憾的是%ROWTYPE
是一个PL / SQL结构,因此您无法使用它来定义模式级表类型。
然后你可以这样做:
SELECT * FROM TABLE(Emp_PKG.F_Emp_Select(<optional versionId>));
...或在联接中使用它:
SELECT ... FROM ...
INNER JOIN TABLE(TEST.Emp_PKG.F_Emp_Select(...)) ON ...
答案 1 :(得分:2)
假设你的目标是返回一个集合,而不是一个临时表,它比你的例子复杂一点
CREATE OR REPLACE PACKAGE emp_pkg
AS
TYPE emp_typ IS TABLE OF emp%rowtype index by binary_integer;
FUNCTION get_emps
RETURN emp_typ;
END;
CREATE OR REPLACE PACKAGE BODY emp_pkg
AS
FUNCTION get_emps
RETURN emp_typ
IS
l_emps emp_typ;
BEGIN
SELECT *
BULK COLLECT INTO l_emps
FROM emp;
RETURN l_emps;
END;
END;
现在,从架构上讲,我会非常非常关注一个解决方案,该解决方案涉及从表中选择所有数据到PL / SQL集合中。 PL / SQL集合必须完全存储在会话的SGA中,这是相对昂贵的服务器RAM。如果您的表中有数千或数万行,那么服务器上的空间可能相当大,特别是如果可能有许多不同的会话都在大致同一时间调用这些过程。如果你的表都有几百行,一次只有一个会话将使用这些函数,也许这种方法就足够了。