Oracle 未找到多个 Select Into 语句的数据

Posted

技术标签:

【中文标题】Oracle 未找到多个 Select Into 语句的数据【英文标题】:Oracle No Data Found for several Select Into statements 【发布时间】:2015-05-20 21:16:18 【问题描述】:

我在 PL/SQL 过程中使用了几个连续的 SELECT INTO 语句。如果这些 Select 语句中的任何一个导致 NO DATA FOUND,我想以一致的方式处理错误。有没有办法在同一过程中为多个 Select 语句使用一个 EXCEPTION 例程?我想知道哪个特定的 Select 失败,以便我可以给出正确的消息。

Declare
  l_smtp_hostname varchar2(1024);
  l_smtp_port varchar2(1024);
  l_music_db_site varchar2(1024);
Begin
    Select lu_value into l_smtp_hostname from mail_lookup 
          Where lu_type = 'smtp_hostname';
    Select lu_value into l_smtp_port from mail_lookup 
          Where lu_type = 'smtp_port';
    Select lu_value into l_music_db_site from mail_lookup 
          Where lu_type = 'music_db_site';
End;

感谢您查看此内容。

【问题讨论】:

我无权访问表创建命令。但我认为更喜欢动态使用列类型而不是使用 varchar2 会很聪明。 (即使它的内存使用经过优化,只会占用实际使用的空间)。关于 %TYPE 的信息在PL/SQL User's Guide 中。 【参考方案1】:

实际上,可能不会。

您可以有一个异常处理程序,但您将不知道哪一步失败了。您可能会从错误堆栈中获取错误的行号,然后解析来自dba_source 的数据(假设您确实有一个存储过程而不是匿名 PL/SQL 块)以找到该语句。但这是一项繁重的工作。

Declare
  l_smtp_hostname varchar2(1024);
  l_smtp_port varchar2(1024);
  l_music_db_site varchar2(1024);
Begin
    Select lu_value into l_smtp_hostname from mail_lookup 
          Where lu_type = 'smtp_hostname';
    Select lu_value into l_smtp_port from mail_lookup 
          Where lu_type = 'smtp_port';
    Select lu_value into l_music_db_site from mail_lookup 
          Where lu_type = 'music_db_site';
Exception
  When no_data_found
  Then
    <<do something>>
End;

您可以添加一个变量来跟踪您在流程中的位置。这可行,但可能会导致一些丑陋的代码

Declare
  l_smtp_hostname varchar2(1024);
  l_smtp_port varchar2(1024);
  l_music_db_site varchar2(1024);

  l_tracker varchar2(30);
Begin
    l_tracker := 'smtp_hostname';
    Select lu_value into l_smtp_hostname from mail_lookup 
          Where lu_type = l_tracker;

    l_tracker := 'smtp_port';
    Select lu_value into l_smtp_port from mail_lookup 
          Where lu_type = l_tracker;

    l_tracker := 'music_db_site';
    Select lu_value into l_music_db_site from mail_lookup 
          Where lu_type = l_tracker;
Exception
  When no_data_found
  Then
    dbms_output.put_line( 'Error at ' || l_tracker );
    <<do something>>
End;

大多数情况下,您希望分别处理每个异常。通常通过调用记录错误的过程。

Declare
  l_smtp_hostname varchar2(1024);
  l_smtp_port varchar2(1024);
  l_music_db_site varchar2(1024);
Begin
  begin
    Select lu_value into l_smtp_hostname from mail_lookup 
          Where lu_type = 'smtp_hostname';
  exception
    when no_data_found then
      log_error( 'smtp_hostname', <<other parameters>> );
  end;

  begin
    Select lu_value into l_smtp_port from mail_lookup 
          Where lu_type = 'smtp_port';
  exception
    when no_data_found then
      log_error( 'smtp_port', <<other parameters>> );
  end;

  begin
    Select lu_value into l_music_db_site from mail_lookup 
          Where lu_type = 'music_db_site';
  exception
    when no_data_found then
      log_error( 'music_db_site', <<other parameters>> );
  end;
End;

当然,您可以将该代码分解为一个函数,该函数接受 lu_type 并返回 lu_value,而不是复制代码块中的代码。

Declare
  l_smtp_hostname varchar2(1024);
  l_smtp_port varchar2(1024);
  l_music_db_site varchar2(1024);

  function get_lu_value( p_lu_type in mail_lookup.lu_type%type )
    return mail_lookup.lu_value%type
  is
    l_val mail_lookup.lu_value%type;
  begin
    select lu_value
      into l_val
      from mail_lookup
     where lu_type = p_lu_type;

    return l_val;
  exception
    when no_data_found
    then
      <<do something>>
  end;
Begin
  l_smtp_hostname := get_lu_value( 'smtp_hostname' ); 
  l_smtp_port := get_lu_value( 'smtp_port' ); 
  l_music_db_site := get_lu_value( 'music_db_site' ); 
End;

【讨论】:

嗨贾斯汀。谢谢您的帮助。我尝试过这个。最后一个示例,即具有该功能的示例,运行良好。【参考方案2】:

您可以将每个选择包装在它自己的块中并调用一个常见的异常处理程序,或者执行类似的操作,在您执行代码时设置一个位置变量,如果发生异常,记录该位置的值,以便你知道它失败的地方是这样的:

Declare
  l_smtp_hostname varchar2(1024);
  l_smtp_port     varchar2(1024);
  l_music_db_site varchar2(1024);
  v_location      varchar2(50);
  err_nbr         NUMBER;         -- Holds a SQL error number if an exception occurs.
  err_msg         VARCHAR2(1000); -- Holds a SQL error message if an exception occurs.
  err_string      VARCHAR2(2000);
Begin
    v_location := 'location_1';
    Select lu_value into l_smtp_hostname from mail_lookup 
          Where lu_type = 'smtp_hostname';
    v_location := 'location_2';
    Select lu_value into l_smtp_port from mail_lookup 
          Where lu_type = 'smtp_port';
    v_location := 'location_3';
    Select lu_value into l_music_db_site from mail_lookup 
          Where lu_type = 'music_db_site';
Exception
  When NO_DATA_FOUND then
    err_nbr    := SQLCODE;
    err_msg    := SUBSTR(SQLERRM, 1, 1000);
    err_string := 'ERROR: ' || err_nbr || ' occurred: ' || err_msg;

    UTL_MAIL.send(sender     => 'program_name@your_company.com', 
                  recipients => 'support_team@your_company.com', 
                  subject    => 'ERROR in <program_name>', 
                  message    => 'Select failed at: ' || v_location || CHR(10)||CHR(10)||err_string);                                  

  RAISE; -- re-raise the error so the program fails.
End;

【讨论】:

嗨,加里。我试过这个。它工作得很好。这更多的是我对这种特殊需求的考虑。感谢您的帮助。

以上是关于Oracle 未找到多个 Select Into 语句的数据的主要内容,如果未能解决你的问题,请参考以下文章

关于oracle存储过程select into 未找到数据问题

Oracle PL/SQL - ORA-01403 使用“SELECT INTO”时“未找到数据”

Access 2013 VBA - 后续 SELECT 查询未找到来自 INSERT INTO 的新记录

在ORACLE触发器中想使用into 语句给一个变量赋值,但是查询出来的值可能为空,如何避免报错未找到任何数据

使用 Oracle Insert Into...Values 插入多个值

Oracle中insert into select和select into的区别