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

时间:2015-01-05 11:52:33

标签: plsql

我有一些表,并且当指定过滤器的记录存在时尝试获取主键,否则我需要我的函数返回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;

哪一个更好?或者可能有不同的方法?

3 个答案:

答案 0 :(得分:1)

如果多个行符合条件,那么您的第一个示例将引发TOO_MANY_ROWS异常。第二个示例将遍历与条件匹配的所有行,并返回最后一个的ID。您可以选择自己喜欢的行为。

分享并享受。

答案 1 :(得分:1)

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

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

以下是我的表现:

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引擎可以在多次执行时为相同的输入返回不同的结果。第一个例子(修改为使用聚合函数)仍然是一种更清晰的方式来实现你想要的东西。

答案 2 :(得分:1)

因此,如果您的问题是,哪种SQL样式比查看以下实验更快: 这段代码以三种不同的方式剪断了10000 x“从双重中选择虚拟”:

  1. 显式光标
  2. 隐式光标
  3. select ... into ...(实际上它也是一个隐式游标)
  4. 以下是代码:

    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 Server上的Oracle 11.2 SE)上运行此代码,结果为:

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

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