哪种方法更适合处理 PL/SQL 中的缺失数据

Which approach is better for processing missing data in PL/SQL

我有一些 table 并尝试在指定过滤器的记录存在时获取主键,否则我需要我的函数 return NULL 值。

我可以这样做

function getIdIfExists(pParam number) return number is
  resultId number;
begin
  begin
    select ID into resultId from mytable where some_condition = pParam and rownum = 1;
    exception when NO_DATA_FOUND then
       resultId := NULL;
  end;

  return resultId;
end;

或者这样:

function getIdIfExists(pParam number) return number is
  resultId number := NULL;
begin
  for item in (select * into resultId from mytable where some_condition = pParam) loop
    resultId := item.ID;
    exit;
  end loop;
  return resultId;
end;

那么哪个更好呢?或者可能有不同的方法?

如果不止一行符合条件,您的第一个示例将引发 TOO_MANY_ROWS 异常。第二个示例将遍历所有匹配条件的行和 return 最后一行的 ID。您选择喜欢哪种行为。

分享和享受。

第一个(使用 SQL 而不是循环)明显更好,因为您使用 SQL 引擎搜索数据而不是手动检查 [=28] 中的每一行=] 使用 PL/SQL。使用 PL/SQL 时的基本规则是,如果您可以在 SQL 中使用,请不要在 PL/SQL 中使用。

但是,您的第一个示例将需要修改以使用 MAX 等聚合函数来确保只有一行 returned,否则多行将引发异常。

这是我的做法:

FUNCTION getIdIfExists(p_id NUMBER) RETURN NUMBER
IS
   resultId NUMBER;
BEGIN
   SELECT   MAX(id)
   INTO     resultId
   FROM     mytable
   WHERE    some_condition = p_id;

   RETURN resultId;
END;

编辑:我实际上误读了第二个例子,没有看到你在那里有一个 WHERE 子句。鉴于此,第二个示例实际上存在错误,因为它没有 ORDER BY 因此给定多个匹配 SQL 引擎可以 return 多次执行相同输入的不同结果。第一个示例(修改为使用聚合函数)仍然是一种更简洁的方法来实现您想要的。

因此,如果您的问题是 SQL 的哪种样式比查看以下实验更快: 此代码以三种不同方式截断循环 10000 x "select dummy from dual":

  1. 显式游标
  2. 隐式游标
  3. select ... into ...(其实也是隐式游标)

代码如下:

procedure cursor_style_compare is
    l_start_time number;
    l_duration   number;
    l_dummy      dual.dummy%type;

    cursor c_explicit is
        select dummy from dual;
 begin
    -- Explicit Cursors:
    l_start_time := dbms_utility.get_time;
    for i in 1 .. 10000 loop
        for c1 in c_explicit loop
            null;
        end loop;
    end loop;
    l_duration := dbms_utility.get_time - l_start_time;
    dbms_output.put_line('Explicit Cursor:     ' || to_char(l_duration));

    -- Implicit Cursors (1):
    l_start_time := dbms_utility.get_time;
    for i in 1 .. 10000 loop
        for c1 in (select dummy from dual) loop
            null;
        end loop;
    end loop;
    l_duration := dbms_utility.get_time - l_start_time;
    dbms_output.put_line('Implicit Cursor (1): ' || to_char(l_duration));

    -- Implicit Cursors (2):
    l_start_time := dbms_utility.get_time;
    for i in 1 .. 10000 loop
        select dummy into l_dummy from dual;
    end loop;
    l_duration := dbms_utility.get_time - l_start_time;
    dbms_output.put_line('Implicit Cursor (2): ' || to_char(l_duration));

end;

如果我 运行 我的本地数据库上的这段代码(Windows 服务器上的 Oracle 11.2 SE),结果是:

Explicit Cursor:     43
Implicit Cursor (1): 41
Implicit Cursor (2): 31

因此,如果结果只是一行,那么简单的 "select ... into ..." 是获取数据的最快方法。这也是Oracle官方的推荐: Working with Cursors (by Steven Feuerstein)