【问题标题】:Oracle SQL: Why is my function outputting null?Oracle SQL:为什么我的函数输出为空?
【发布时间】:2012-09-22 06:00:13
【问题描述】:
CREATE OR REPLACE FUNCTION get_status_by_member_id
(p_member_id NUMBER) 
RETURN CHAR
AS
  v_status CHAR(1);
BEGIN
  select status
  into v_status
  from members
  where member_id = p_member_id;
  if v_status is null then
    return v_status || 'N';
  else
     return v_status;
  end if;
END get_status_by_member_id;

【问题讨论】:

  • FWIW - 如果您提供一些上下文和您对问题的直觉,这将很有帮助。
  • member_id 的类型是什么?表中可能有重复项吗?换句话说,也许查询返回了一个错误,所以由于过早返回和未检测到的错误,您得到了 NULL。
  • 你能用desc membersselect status,member_id from members; 的小sn-p 输出更新问题吗?
  • @Bianca,你说even if I do return 'N', it outputs null. 看起来你的显示代码可能是嫌疑人。

标签: sql oracle plsql


【解决方案1】:

您的问题有时是由 Oracle 的一个恼人的怪癖引起的。也就是说,如果在 SQL 中调用 PL/SQL 函数并出现错误,则返回 null,而不是其他任何内容。

如果我创建一个非常简单的表...

create table a ( b number, c varchar2(1) );
insert into a values (1,'Y');

... 和两个功能。一种没有异常处理

create or replace function tmp_ben_fn (PId number) return char is
   l_status varchar2(1);   
begin  

   select c
     into l_status
     from a
    where b = PId;

   return coalesce(l_status, 'N');

end;
/

还有一个具有异常处理功能。

create or replace function tmp_ben_fn2 (PId number) return char is
   l_status varchar2(1);   
begin  

   select c
     into l_status
     from a
    where b = PId;

   return coalesce(l_status, 'N');

   exception when no_data_found then
      return 'A';

end;
/

然后,我们使用这两个函数来选择数据。请记住,我们只有一行,因此我们只希望返回 YN

SQL> -- Expected output Y
SQL> select tmp_ben_fn(1) from dual;

TMP_BEN_FN2(1)
-------------------------------------------------

Y

SQL> -- Expected output, Error no_data_found
SQL> -- as row 2 does not exist.
SQL> select tmp_ben_fn(2) from dual;

TMP_BEN_FN(2)
-------------------------------------------------



SQL> -- Expected output, the same as tmp_ben_fn
SQL> select tmp_ben_fn2(2) from dual;

TMP_BEN_FN2(2)
-------------------------------------------------

A

SQL>

正如您在没有错误处理的函数中看到的那样,当发生no_data_found 异常时,将返回null。当我们捕获异常时,我们会得到预期的A

我怀疑您尝试选择的 member_id 不存在。

作为一般规则:始终注意何时可能发生异常,select into... 是一个特别令人担忧的示例,它有机会选择太多行和没有行。如果您的表在 member_id 上是唯一的,那么您应该按如下方式更改您的函数:

CREATE OR REPLACE FUNCTION get_status_by_member_id (p_member_id NUMBER) 
RETURN CHAR IS
  v_status CHAR(1);
BEGIN
  select status
  into v_status
  from members
  where member_id = p_member_id;

  return v_status;

-- If the member_id does not exist
-- return N
exception when no_data_found then
   return 'N';
END get_status_by_member_id;

【讨论】:

    【解决方案2】:

    尝试在代码中添加异常处理程序,如下所示:

    CREATE OR REPLACE FUNCTION get_status_by_member_id 
      (p_member_id NUMBER) RETURN CHAR 
    as 
      v_status CHAR(1); 
    begin 
      BEGIN
        select status 
          into v_status 
          from members 
          where member_id = p_member_id;
      EXCEPTION
        WHEN NO_DATA_FOUND THEN
          v_status := NULL;
        WHEN TOO_MANY_ROWS THEN
          v_status := NULL;
      END;
    
      if v_status is null then 
        return 'N'; 
      else 
        return v_status; 
      end if; 
    end get_status_by_member_id; 
    

    这将处理没有匹配 p_member_id 的数据,或者有多个匹配 p_member_id 的行的情况。这可能会或可能不会纠正您看到的问题。如果您编辑您的帖子并添加您正在使用的调用get_status_by_member_id 的代码,将会很有帮助。

    分享和享受。

    【讨论】:

    • 如果SELECT 中出现NO DATA FOUND 错误,则函数调用将在执行SELECT INTO 时中止并失败。但在 OPs 的情况下,它执行成功但返回NULL。我同意异常处理部分,但我也认为这不是导致问题的原因。
    • @Annjawn:我的想法是,如果从客户端程序调用该函数并且未检查返回码等,则完全有可能该函数执行正确并返回 NULL。这是我能想象到的唯一一种情况,这个函数可以“返回”NULL,这也是我尝试在 SQL 周围包装异常处理程序的原因。
    猜你喜欢
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2020-07-15
    • 2013-03-26
    相关资源
    最近更新 更多