执行查询之前验证结果

时间:2019-05-27 03:43:51

标签: oracle stored-procedures plsql

运行存储过程以获取某些行时,首先,我想在发送结果之前验证查询是否将返回一行,其次,如果无需两次运行相同的查询就可以进行验证。

我正在使用游标存储产生的结果,因此我尝试了游标属性%ROWCOUNT%NOTFOUND。但不是很有效。另外,我想做到这一点而不在光标上运行循环。

procedure MODULE_LIST_GK(p_module_Id IN MODULE_LIST.MODULE_ID% TYPE,
                                     p_Error_Code     out nvarchar2,
                                     p_Error_Msg      out nvarchar2,
                                     p_Cursor         out sys_refcursor)   IS
 BEGIN
    OPEN p_Cursor FOR
       SELECT A.MODULE_ID,
         A.MODULE_NM,
         A.AUTH_STATUS_ID
         FROM MODULE_LIST A
         WHERE A.MODULE_ID=p_module_Id;

       SELECT COUNT(MODULE_ID)
       INTO v_row_num
        FROM MODULE_LIST A
        WHERE A.MODULE_ID=p_module_Id;

       IF v_row_num=0 THEN
         p_Error_Code := SQLCODE;
         p_Error_Msg := 'Does not Exists';
         Return;
       end IF;
    EXCEPTION
      WHEN OTHERS THEN
        p_error_code:= SQLCODE;
        p_error_msg := SQLERRM;
  END MODULE_LIST_GK;

2 个答案:

答案 0 :(得分:3)

您的实施过程中有几点可以改进。

第一,如果您期望对于很多参数返回的光标为空, 比先检查空光标,然后再检查光标。反之亦然。

如何检查光标是否为空?不幸的是,您必须获取第一行才能进行验证。

 open l_cur for
   select id, status from tab where id = p_id; 
 fetch l_cur into l_id, l_status;
 if l_cur%NOTFOUND then
    p_Error_Msg := 'Does not Exists';
    Return;
 end if;

此检查比经常使用的count(*)更有效,因为它只考虑前几行,而不考虑光标中的所有行

如果检查失败,您就准备好了,否则,请简单地打开游标并返回它。

 open  l_cur for
   select id, status from tab where id = p_id; 
   p_Cursor := l_cur;

我想到了另外两个想法。

如果数据库非常动态,则应该重新采用通用方法。 当其他会话删除检查和游标第二次打开之间的某行时,您将如何处理?

最后考虑返回异常,而不是返回代码。

答案 1 :(得分:1)

为了知道游标是否包含行,必须将其打开并获取第一行。一旦完成此操作,就不再需要返回该游标了,因为接收者将无法获取该第一行,因为游标已经指向该行了。

因此,您必须选择两次。您要做的是在此处使用ROWNUMEXISTS子句向DBMS显示您对更多行都不感兴趣。这样可以极大地加快查询速度。

PROCEDURE module_list_gk(p_module_id   IN   MODULE_LIST.MODULE_ID%TYPE,
                         p_error_code  OUT  NVARCHAR2,
                         p_error_msg   OUT  NVARCHAR2,
                         p_cursor      OUT  SYS_REFCURSOR) IS
  v_count INTEGER;
BEGIN
  SELECT COUNT(*)
  INTO v_count
  FROM module_list
  WHERE module_id = p_module_Id
  AND ROWNUM = 1;

  IF v_count = 0 THEN
    p_error_code := 0; -- Or -1403 for NO DATA FOUND if you like
    p_error_msg := 'Does not Exists';
    RETURN;
  END IF;

  OPEN p_Cursor FOR
    SELECT module_id, module_nm, auth_status_id
    FROM module_list
    WHERE module_id = p_module_id;

EXCEPTION WHEN OTHERS THEN
  p_error_code:= SQLCODE;
  p_error_msg := SQLERRM;
END module_list_gk;

第一个查询的SQLCODE将会是0(SELECT COUNT(*)返回一行,其中包含找到的记录数-因此没有错误)。这就是为什么您应该决定显式返回零或某些错误代码(例如-1403)的原因。

EXISTS相同:

BEGIN
  SELECT CASE WHEN EXISTS
  (
    SELECT NULL
    FROM module_list
    WHERE module_id = p_module_Id
  ) THEN 1 ELSE 0 END
  INTO v_count
  FROM DUAL;

  IF v_count = 0 THEN