参考光标例外

时间:2015-08-07 15:27:51

标签: oracle plsql oracle11g

我有几个问题arounbd ref_cursors。下面是一个ref_cursor,它根据传入的内容向Unix调用脚本返回一行,虽然select看起来有点乱,但它按预期工作。

我的第一个问题是,在选择中我加入查找表以检索单个查找值' trigram'并且在测试中发现此连接偶尔会失败,因为没有值存在。我试图用no_data_found捕获它,当其他异常时,但这似乎不起作用。

理想情况下,如果连接失败,我仍然希望将值返回到ref_cursor,但添加类似于' No Trigram'进入trigram字段 - 主要是我想捕获异常。

我的第二个问题是关于ref_cursors的更一般的问题 - 虽然我最初在自己的程序中创建了它,但它很可能被主处理程序多次调用,其中一个条件需要单独选择但是程序只有在调用时才返回一个ref_cur,procdure ref_cur out可以与2个查询相关联。

CREATE OR REPLACE PROCEDURE OPC_OP.SiteZone_status
    (in_site_id IN AW_ACTIVE_ALARMS.site_id%TYPE
    ,in_zone_id IN AW_ACTIVE_ALARMS.zone_id%TYPE
    ,in_mod     IN AW_ACTIVE_ALARMS.module%TYPE
    ,p_ResultSet        OUT  TYPES.cursorType
    )
AS
 BEGIN
 OPEN p_ResultSet FOR
 SELECT a.site_id,'~',a.zone_id,'~',b.trigram,'~',a.module,'~',a.message_txt,'~',a.time_stamp
 FROM AW_ACTIVE_ALARMS a, AW_TRIGRAM_LOCATION b
 WHERE a.site_id = b.site_id 
 AND a.zone_id = b.zone_id
 AND a.site_id = in_site_id 
 AND a.zone_id = in_zone_id
 AND a.module LIKE substr(in_mod,1,3)||'%'
 AND weight = (select max(weight) from AW_ACTIVE_ALARMS c
               WHERE c.site_id = in_site_id 
               AND c.zone_id = in_zone_id
               AND c.module LIKE substr(in_mod,1,3)||'%');
EXCEPTION
    WHEN OTHERS
    THEN
        DBMS_OUTPUT.PUT_LINE('No Data Found');

END SiteZone_status;

我已修改我的代码以采用所提供的答案,现在这可以像我们的包中的独立程序一样工作,当使用以下命令通过UNIX脚本调用时:     v_process_alarm = $(sqlplus -s user / pass<     设置colsep','     设置lineize 500     设置页面0反馈关闭;     set serveroutput on;     VARIABLE resultSet REFCURSOR     EXEC alarm_pkg.rtn_active_alarm($ site,$ zone,$ module,:resultSet);     PRINT:resultSet     EOF     )

然而,返回ref游标的过程是从主处理过程调用的,因为我只想在满足某些条件时返回值。我已经在我的主程序中添加了一个refcurosr并设置了一个匹配的变量,然后我从这里调用我的ref cursor程序,但这无法编译 消息'呼叫中的参数数量或类型错误'

我的问题是在程序中调用没有refcursor的过程然后将这些值从那里返回到调用脚本的正确方法是什么。

2 个答案:

答案 0 :(得分:2)

您可以在查找表中使用左外连接,如果使用ANSI连接语法而不是Oracle的旧语法,则更清晰。如果AW_TRIGRAM_LOCATION中没有记录,则b.trigram将为空,然后您可以使用NVL分配虚拟值:

 OPEN p_ResultSet FOR
 SELECT a.site_id,'~',a.zone_id,'~',NVL(b.trigram, 'No Trigram'),'~',
   a.module,'~',a.message_txt,'~',a.time_stamp
 FROM AW_ACTIVE_ALARMS a
 LEFT JOIN AW_TRIGRAM_LOCATION b
 ON b.site_id = a.site_id 
 AND b.zone_id = a.zone_id
 WHERE a.zone_id = in_zone_id
 AND a.module LIKE substr(in_mod,1,3)||'%'
 AND weight = (select max(weight) from AW_ACTIVE_ALARMS c
               WHERE c.site_id = in_site_id 
               AND c.zone_id = in_zone_id
               AND c.module LIKE substr(in_mod,1,3)||'%');

只有当你从中获取光标时才会获得NO_DATA_FOUND光标(取决于实际消耗的光标)。无论如何捕获WHEN OTHERS是个坏主意 - 你想要抓住WHEN NO_DATA_FOUND,尽管这在这里没有用。使用dbms_output报告错误依赖于客户端启用其显示,这通常是您无法假设的。

答案 1 :(得分:2)

在您从游标中获取之前,Oracle不知道查询是否会返回行。并且查询返回0行不是错误。因此,打开游标永远不会得到no_data_found异常。如果您执行select into局部变量之类的操作,那么您只会得到它,在这种情况下,返回0或多于1行的查询是错误的。

听起来你想对outer join表做AW_TRIGRAM_LOCATION而不是当前的内连接。即使aw_trigram_location中没有匹配的行,这也将返回其他表中的数据。这看起来像这样(我不知道为什么每隔一列都是一个硬编码的波形符,这看起来格外奇怪)

SELECT a.site_id,'~',
       a.zone_id,'~',
       nvl(b.trigram, 'No Trigram Found'),'~',
       a.module,'~',
       a.message_txt,'~',
       a.time_stamp
  FROM AW_ACTIVE_ALARMS a
       LEFT OUTER JOIN AW_TRIGRAM_LOCATION b
         ON( a.site_id = b.site_id AND 
             a.zone_id = b.zone_id )
 WHERE a.site_id = in_site_id 
   AND a.zone_id = in_zone_id
   AND a.module LIKE substr(in_mod,1,3)||'%'
   AND weight = (select max(weight) 
                   from AW_ACTIVE_ALARMS c
                  WHERE c.site_id = in_site_id 
                    AND c.zone_id = in_zone_id
                    AND c.module LIKE substr(in_mod,1,3)||'%');

我不太确定我理解你的上一个问题。您当然可以在您的过程中根据输入参数运行不同的查询。像

这样的东西
IF( <<some condition>> )
THEN
  OPEN p_ResultSet FOR <<query 1>>
ELSE
  OPEN p_ResultSet FOR <<query 2>>
END IF;

这样做是否有意义而不是添加其他谓词或创建单独的程序是一个你必须回答的问题。