我的 PL/SQL 代码有问题。
我正在创建一个函数,该函数应返回定义为的自定义类型:
create TYPE rc_rman_guaranteed_backups_table_type AS TABLE OF RCATPROD.rc_rman_guaranteed_backups_type;
create TYPE rc_rman_guaranteed_backups_type AS OBJECT (
REG_DB_UNIQUE_NAME VARCHAR2(32),
MIN_GUARANTEED_DAYS DATE,
MIN_GUARANTEED_DATE DATE
);
函数DDL是:
create or replace FUNCTION RC_RMAN_GUARANTEED_BACKUPS_func RETURN RCATPROD.rc_rman_guaranteed_backups_table_type PIPELINED IS
query_string VARCHAR2(32000);
result_cursor SYS_REFCURSOR;
CURSOR query_usr IS select username from dba_users where (username like 'RMAN%TSM' or username like 'RMAN%CV') and account_status = 'OPEN' order by 1;
i number;
REG_DB_UNIQUE_NAME VARCHAR2(32);
MIN_GUARANTEED_DAYS DATE;
MIN_GUARANTEED_DATE DATE;
BEGIN
i:=0;
query_string := '';
FOR usr IN query_usr LOOP
REG_DB_UNIQUE_NAME:=substr(usr.username, 6, 8);
IF i=0 THEN
query_string := 'select '''||REG_DB_UNIQUE_NAME||''', trunc(sysdate-min(completion_time)), min(completion_time) from '||usr.username||'.bs where incr_level=0 ';
i:=i+1;
ELSE
query_string := query_string||'union all select '''||REG_DB_UNIQUE_NAME||''', trunc(sysdate-min(completion_time)), min(completion_time) from '||usr.username||'.bs where incr_level=0 ';
END IF;
END LOOP;
query_string := query_string||'order by 1';
OPEN result_cursor FOR query_string;
LOOP
FETCH result_cursor INTO REG_DB_UNIQUE_NAME,MIN_GUARANTEED_DAYS,MIN_GUARANTEED_DATE;
EXIT WHEN result_cursor%NOTFOUND;
PIPE ROW (RCATPROD.rc_rman_guaranteed_backups_type(REG_DB_UNIQUE_NAME,MIN_GUARANTEED_DAYS,MIN_GUARANTEED_DATE));
END LOOP;
CLOSE result_cursor;
RETURN;
END;
一切都已正确编译,但是,当我尝试选择函数结果时,出现以下错误:
select * from table(RCATPROD.RC_RMAN_GUARANTEED_BACKUPS_func);
ORA-00942: 表贝拉或远景不一致 ORA-06512: a “RCATPROD.RC_RMAN_GUARANTEED_BACKUPS_FUNC”,第 22 行 00942. 00000 - “表或视图不存在” *原因:
*行动:
我尝试输入输出 query_string 并且结果是正确的,所以我认为问题出在 OPEN result_cursor ... 块内。
这很奇怪,因为我以同样的方式定义了其他函数,而且它们没问题。
请您帮忙理解重点在哪里?
提前谢谢您。
Oracle 抱怨表(或视图)不存在。
该代码中有两个 select 语句:
有人从
dba_users
获取数据 - 您有权限这样做吗?请注意,这是一个函数,一个 named PL/SQL 过程;如果您通过 role获得了
dba_users
的权限,那将不起作用 - 您必须直接授予它们
另一个假设每个模式中都有
bs
表,其用户名是通过游标获取的
答案应该帮助您决定要做什么。
根据错误行号 (22),我将赌注押在
bs
表的问题上。
假设您有权限查看所有表格:
在 Oracle 中,如果使用不带引号的标识符,则 Oracle 会隐式地将标识符转换为大写。因此,如果您从
dba_users
读取一个小写或混合大小写标识符的值,然后在 SELECT
查询中使用不带引号的值,那么它将隐式转换为大写,并且将找不到用户。
与您的问题无关,但如果您的函数返回多行并且您使用查询,那么您的代码仍然是一个错误:
select *
from table(RCATPROD.RC_RMAN_GUARANTEED_BACKUPS_func)
where ROWNUM = 1;
然后函数将终止,而不会读取游标中的所有值,并且游标不会关闭。要处理此问题,您需要捕获
NO_DATA_NEEDED
异常并关闭光标。
使用带引号的标识符并捕获
NO_DATA_NEEDED
异常:
create or replace FUNCTION RC_RMAN_GUARANTEED_BACKUPS_func
RETURN RCATPROD.rc_rman_guaranteed_backups_table_type PIPELINED
IS
query_string VARCHAR2(32000) := NULL;
CURSOR query_usr IS
select username
from dba_users
where (username like 'RMAN%TSM' or username like 'RMAN%CV')
and account_status = 'OPEN'
order by 1;
result_cursor SYS_REFCURSOR;
i number := 0;
REG_DB_UNIQUE_NAME VARCHAR2(32);
MIN_GUARANTEED_DAYS DATE;
MIN_GUARANTEED_DATE DATE;
BEGIN
FOR usr IN query_usr LOOP
REG_DB_UNIQUE_NAME:=substr(usr.username, 6, 8);
IF i=0 THEN
query_string := 'select '''||REG_DB_UNIQUE_NAME||''', trunc(sysdate-min(completion_time)), min(completion_time) from "'||usr.username||'".bs where incr_level=0 ';
i:=i+1;
ELSE
query_string := query_string
|| 'union all select '''||REG_DB_UNIQUE_NAME||''', trunc(sysdate-min(completion_time)), min(completion_time) from "'||usr.username||'".bs where incr_level=0 ';
END IF;
END LOOP;
IF query_string IS NOT NULL THEN
query_string := query_string||'order by 1';
OPEN result_cursor FOR query_string;
LOOP
FETCH result_cursor INTO REG_DB_UNIQUE_NAME,MIN_GUARANTEED_DAYS,MIN_GUARANTEED_DATE;
EXIT WHEN result_cursor%NOTFOUND;
PIPE ROW (RCATPROD.rc_rman_guaranteed_backups_type(REG_DB_UNIQUE_NAME,MIN_GUARANTEED_DAYS,MIN_GUARANTEED_DATE));
END LOOP;
CLOSE result_cursor;
END IF;
EXCEPTION
WHEN NO_DATA_NEEDED THEN
CLOSE result_cursor;
END;
/