我有一些表,并且当指定过滤器的记录存在时尝试获取主键,否则我需要我的函数返回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;
哪一个更好?或者可能有不同的方法?
答案 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“从双重中选择虚拟”:
以下是代码:
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)