首先,您的类型声明不完全正确。
在您的类型T_REC 中,您需要声明VARCHAR2 列的大小。我在这里以100 为例:
TYPE T_REC IS RECORD
(
T_TITLE VARCHAR2(100),
T_YEAR NUMBER(2,1)
);
其次是行
TYPE T_EMP IS TABLE OF T_REC%TYPE;
不正确:T_REC 本身就是一种类型,因此您无需为其指定 %TYPE 属性。请尝试以下方法。
TYPE T_EMP IS TABLE OF T_REC;
您定义函数的方式也存在一些问题:
FUNCTION HIST(V_EMP_ID EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN V_EMP;
BEGIN
-- ...
RETURN 子句需要使用类型,但V_EMP 是局部变量。此外,您需要包含关键字IS 来告诉PL/SQL 编译器以下块构成函数的主体,而不是用分号结束声明。将这些更改放在一起,我们有:
FUNCTION HIST(V_EMP_ID EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN T_EMP
IS
BEGIN
-- ...
用声明解决这些问题后,我们可以查看底部的BEGIN 块。第一个问题是您不能编写SELECT T_TITLE, T_YEAR FROM Z_EMP 来查询包含嵌套表的变量。相反,您必须将其包装在对TABLE 的调用中,即SELECT T_TITLE, T_YEAR FROM TABLE(Z_EMP)。
但是,这样做是行不通的。如果您尝试,您将收到错误PLS-00642: local collection types not allowed in SQL statements。这是因为您不能对仅在 PL/SQL 块中声明的类型运行 SQL 查询。您可以改为使用以下方法循环返回集合中的值:
IF Z_EMP.COUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('There are no records');
ELSE
FOR i IN Z_EMP.FIRST .. Z_EMP.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(Z_EMP(i).T_TITLE || ', ' || Z_EMP(i).T_YEAR);
END LOOP;
END IF;
请注意,在这种情况下,我们需要检查没有记录的集合:如果集合为空,Z_EMP.FIRST 和 Z_EMP.LAST 将是 NULL,您将得到一个 PL/SQL: numeric or value error 尝试使用它们FOR 循环中的范围。另请注意,DBMS_OUTPUT.PUT_LINE 仅接受一个参数:为避免此处出现错误,我将这两个值连接在一起并在它们之间使用逗号。
或者,如果您真的想使用 SQL 查询来读取函数返回的值,则需要做更多的工作。您必须在 PL/SQL 块之外声明类型 T_REC 和 T_EMP,如下所示:
CREATE TYPE T_REC IS OBJECT
(
T_TITLE VARCHAR2(100 CHAR),
T_YEAR NUMBER(2,1)
);
/
CREATE TYPE T_EMP IS TABLE OF T_REC;
/
然后,您将在块中删除这些类型的声明。您还必须调整函数内的查询:而不是选择
SELECT JOB_TITLE T_TITLE, ROUND((END_DATE - START_DATE) / 365,1) T_YEAR
并且将这些字段映射到记录中,您必须从每个选定的行显式创建一个 T_REC 对象:
SELECT T_REC(JOB_TITLE, ROUND((END_DATE - START_DATE) / 365,1))
完成此操作后,底部的循环可以更改为以下内容:
FOR C IN (SELECT T_TITLE, T_YEAR FROM TABLE(Z_EMP))
LOOP
DBMS_OUTPUT.PUT_LINE(C.T_TITLE || ', ' || C.T_YEAR);
END LOOP;
如果您愿意,也可以去掉检查Z_EMP.COUNT = 0:如果Z_EMP 为空,上述循环不会报告错误,尽管它不会生成任何输出。