Oracle 函数返回自定义类型不起作用

问题描述 投票:0回答:2

我的 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 function plsql return oracle19c
2个回答
1
投票

Oracle 抱怨表(或视图)不存在。

该代码中有两个 select 语句:

  • 有人从

    dba_users
    获取数据 - 您有权限这样做吗?请注意,这是一个函数,一个 named PL/SQL 过程;如果您通过
    role
    获得了 dba_users 的权限,那将不起作用 - 您必须直接授予它们

  • 另一个假设每个模式中都有

    bs
    表,其用户名是通过游标获取的

    • 问题1:你确定存在这样的表吗?
    • 问题 2:您是否有权限从当前用户访问这些表?

    答案应该帮助您决定要做什么。

根据错误行号 (22),我将赌注押在

bs
表的问题上。


0
投票

假设您有权限查看所有表格:

  1. 在 Oracle 中,如果使用不带引号的标识符,则 Oracle 会隐式地将标识符转换为大写。因此,如果您从

    dba_users
    读取一个小写或混合大小写标识符的值,然后在
    SELECT
    查询中使用不带引号的值,那么它将隐式转换为大写,并且将找不到用户。

  2. 与您的问题无关,但如果您的函数返回多行并且您使用查询,那么您的代码仍然是一个错误:

    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;
/
© www.soinside.com 2019 - 2024. All rights reserved.