通过添加嵌入在 PL-SQL(Oracle 函数)中的 select 子句来处理异常

Posted

技术标签:

【中文标题】通过添加嵌入在 PL-SQL(Oracle 函数)中的 select 子句来处理异常【英文标题】:Handling exceptions by adding select clause embedded inside in PL-SQL(Oracle functions) 【发布时间】:2020-03-09 16:20:12 【问题描述】:

我必须在 oracle 中设计一个函数(日期输入,数字输出),在给定条件的情况下执行以下三种情况:

case1: 如果 input_date 匹配 monday_date 然后执行 query1(select from where.. and..) with monday_date 作为输入参数。

case2:如果来自 case(1) 的查询没有返回任何行,则创建新变量 max_input_date1 = input_date+1,然后使用 monday_date 和 max_input_date1 作为输入参数执行 query2(with ..select from table1 left join table2 ..)。

case3:如果来自 case(2) 的查询没有返回任何行,则创建新变量 max_input_date2 = input_date+4,然后使用 monday_date 和 max_input_date2 作为输入参数执行 query2( with..select from table1 left join table2 ..)。

我正在尝试使用异常 - NO_DATA_FOUND 移动到每个案例,但看起来 oracle 函数中的异常子句不执行任何“选择”语句 - 我不完全确定,但它对我不起作用,或者我做错了什么。函数进入异常子句后没有返回任何内容。

我正在寻找有关如何使其工作的建议,无论是否使用异常。请帮忙。这就是我的函数到目前为止的样子

CREATE OR
    REPLACE FUNCTION get_dept_no(input_date string)
    RETURN NUMBER
    IS
    dept_no NUMBER;

    max_input_date1 date ;
    max_input_date2 date ;

    delta1 integer := 1;
    delta2 integer := 4;

BEGIN
    SELECT num
    INTO dept_no
    FROM table1
    WHERE aperiod = 201910
      AND trunc(monday_date) = to_date(input_date, 'yyyy-mm-dd');
    RETURN dept_no;
EXCEPTION
     WHEN NO_DATA_FOUND THEN
            max_input_date1 := to_date(input_date, 'yyyy-mm-dd') + delta1;

            WITH max as (
                SELECT *
                FROM table2 adm
                GROUP BY aperiod, num
                )

                SELECT
                       ma.num INTO dept_no
                FROM max ma
                LEFT JOIN table1 yw
                  ON ma.aperiod = yw.aperiod
                  AND ma.num = yw.num
                WHERE trunc(ma.DOJ_date) >= to_date(input_date, 'yyyy-mm-dd')
                  AND trunc(ma.DOJ_date) <= to_date(max_input_date1, 'yyyy-mm-dd');
            raise;
            WHEN NO_DATA_FOUND THEN
                max_input_date2 := to_date(input_date, 'yyyy-mm-dd') + delta2;
                WITH max as (
                SELECT *
                FROM table2 adm
                GROUP BY aperiod, num
                )

                SELECT
                       ma.num INTO dept_no
                FROM max ma
                LEFT JOIN table1 yw
                  ON ma.aperiod = yw.aperiod
                  AND ma.num = yw.num
                WHERE trunc(ma.DOJ_date) >= to_date(input_date, 'yyyy-mm-dd')
                  AND trunc(ma.DOJ_date) <= to_date(max_input_date2, 'yyyy-mm-dd');

return dept_no;
END get_dept_no;

【问题讨论】:

不确定我是否关注您的问题。你的函数到底返回了什么?空? 你不能在同一个EXCEPTION部分处理WHEN NO_DATA_FOUND THEN两次,这将导致错误:“PLS-00483:异常'NO_DATA_FOUND'可能出现在此块中最多一个异常处理程序中”跨度> 请查看How to Ask。将其作为您问题的模板可以大大提高您获得满意答案的机会。在这种情况下,表 DDL 和示例数据以及该数据的预期结果。还有什么结果,但我猜我会冒险“ORA-06503:PL/SQL:函数返回没有值”或“ORA-01403 找不到数据”。 现在,该函数返回一行,满足并执行了 case1,我无法转到 case 2 或 case 3,我需要帮助编写 case 2 和 case 3。当函数进入异常时,它不会在异常部分执行查询并返回 null,它应该返回一行。 @Acroyear 我编译构建函数@Belayer时没有产生错误,但如果你让我知道有什么不清楚的地方,我可以试着解释一下。 【参考方案1】:

我倾向于编写非常小的函数,只做一件事;有时令人惊讶地涉及更多代码,但消除了复杂性 - 似乎是一个矛盾,但不是真的。在这种情况下,我将打破它 3 个内部函数和一个简单的 main. (是的,你可以在函数里面写一个函数)。

create or replace function get_dept_no(input_date IN string)
    return number
is
    dept_no number;

    max_input_date1 date;
    max_input_date2 date;

    delta1 integer := 1;
    delta2 integer := 4;

    function get_dept_q1
      return number
    is
        dept_q1_result number;
    begin 
        select num
          into dept_q1_result
          from table1
         where aperiod = 201910
           and trunc(monday_date) = to_date(input_date, 'yyyy-mm-dd');
        return dept_q1_result;
    exception 
       when no_data_found then 
            return null; 
    end get_dept_q1;  

    function get_dept_q2
      return number
    is
        dept_q2_result number;
    begin 
      max_input_date1 := to_date(input_date, 'yyyy-mm-dd') + delta1;

      with max as (
           select *
             from table2 adm
            group by aperiod, num
            )
       select ma.num  
        into dept_no
        from max ma
        left join table1 yw
             on  ma.aperiod = yw.aperiod
             and ma.num = yw.num
         where trunc(ma.doj_date) >= to_date(input_date, 'yyyy-mm-dd')
           and trunc(ma.doj_date) <= to_date(max_input_date1, 'yyyy-mm-dd');
        return dept_q2_result;         
    exception 
       when no_data_found then 
            return null; 
    end get_dept_q2;  

    function get_dept_q3
      return number
    is
        dept_q3_result number;
    begin 
      max_input_date1 := to_date(input_date, 'yyyy-mm-dd') + delta1;

      with max as (
           select *
             from table2 adm
            group by aperiod, num
            )
       select ma.num  
        into dept_q3_result
        from max ma
        left join table1 yw
              on  ma.aperiod = yw.aperiod
             and ma.num = yw.num
         where trunc(ma.doj_date) >= to_date(input_date, 'yyyy-mm-dd')
           and trunc(ma.doj_date) <= to_date(max_input_date1, 'yyyy-mm-dd');
         return dept_q1_result;
    exception 
       when no_data_found then 
            return null; 
    end get_dept_q3;       

-- MAIN    
begin
   dept_no := get_dept_q1;

   if dept_no is null 
   then 
      dept_no := get_dept_q2;
   end if;

   if dept_nun is null 
   then 
      dept_no := get_dept_q3;
   end if;                                                     

   if dept_num is null 
   then 
      raise no_data_found; 
   end if;

   return dept_no;
end get_dept_no; 

注意:我没有评估查询,只是重组了原始函数。

【讨论】:

哇,这太棒了!我明白你在说什么,我会试试看。但我认为这是我所需要的,以找到一种构建案例的方法。谢谢你。 @Belayer 会让你知道机智是如何发挥作用的 所以我试了一下,这个结构确实有效,也回答了我的问题。我已将其标记为接受。非常感谢!没有一个案例在函数调用时还没有返回任何结果,但我想我需要弄清楚这里的数据流。就函数而言,它编译和构建没有错误! 乐于助人。这是我经常使用的一种方法。它允许在小块中进行测试/调试,从而使两者都变得更加简单。如果嵌套函数通常有用,我将把它变成模式级别的函数。如果在这里完成,您的主要程序减少到 10-12 左右。免责声明:使用这种方法会产生性能损失。但是,保持代码清晰易懂的能力是值得欣然付出的代价——至少在我获得无法接受的性能水平之前。 完全同意! @Belayer-您能否帮助我理解使用这种结构可能做错了什么,即最初起作用的基本功能(现在是该功能的一种形式)根本不返回任何行?我希望不要为此添加另一个问题.. 我不知道。正如我所指出的,这种结构(我假设您的意思是新的)更容易测试和调试。但这样做需要代码、数据、预期输出和当前输出(即使是没有,如果是这样的话)。为此,我建议发布另一个问题,您可以链接到这个问题。

以上是关于通过添加嵌入在 PL-SQL(Oracle 函数)中的 select 子句来处理异常的主要内容,如果未能解决你的问题,请参考以下文章

Oracle PL-SQL 函数未返回 true

Oracle PL-SQL 函数出现错误 PLS-00103:在预期以下情况之一时遇到符号“SELECT”

如何使用 PL-SQL 在 Oracle 中获取列数据类型

oracle 自定义函数

pl-sql中ordered啥场合使用

Oracle (pl-sql) - 如何从文本中提取特定数据到对象类型变量中?