当结果可能为null时,如何在PL / SQL中选择变量?

时间:2011-08-23 16:01:50

标签: select plsql

有没有办法只运行一次查询以选择变量,考虑到查询可能什么都不返回,那么在这种情况下变量应为null。

目前,我无法直接执行select into变量,因为如果查询什么都不返回,PL / SQL会抱怨变量没有设置。我只能运行两次查询,第一个执行计数,如果计数为零,则将变量设置为null,如果计数为1,则选择变量。

所以代码就像:

v_column my_table.column%TYPE;
v_counter number;
select count(column) into v_counter from my_table where ...;
if (v_counter = 0) then
    v_column := null;
elsif (v_counter = 1) then
    select column into v_column from my_table where ...;
end if;

感谢。

更新: 我没有使用异常的原因是我在分配v_column后仍然有一些跟随逻辑,我必须在异常部分使用goto跳回到下面的代码。我对goto行犹豫不决。

8 个答案:

答案 0 :(得分:104)

您可以通过将变量设置为NO_DATA_FOUND来处理NULL例外。这样,只需要一个查询。

    v_column my_table.column%TYPE;

BEGIN

    BEGIN
      select column into v_column from my_table where ...;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        v_column := NULL;
    END;

    ... use v_column here
END;

答案 1 :(得分:14)

我知道这是一个老话题,但我仍然认为值得回答。

select (
        SELECT COLUMN FROM MY_TABLE WHERE ....
        ) into v_column
from dual;

使用示例:

declare v_column VARCHAR2(100);
begin
  select (SELECT TABLE_NAME FROM ALL_TABLES WHERE TABLE_NAME = 'DOES NOT EXIST')
  into v_column 
  from dual;
  DBMS_OUTPUT.PUT_LINE('v_column=' || v_column);
end;

答案 2 :(得分:7)

使用Cursor FOR LOOP Statement是我最喜欢的方法。

它比使用显式光标更安全,因为您无需记住将其关闭,因此您无法“泄漏”光标。

你不需要“into”变量,你不需要“FETCH”,你不需要捕获和处理“NO DATA FOUND”异常。

试试吧,你永远不会回去。

v_column my_table.column%TYPE;

v_column := null;

FOR rMyTable IN (SELECT COLUMN FROM MY_TABLE WHERE ....) LOOP
  v_column := rMyTable.COLUMN;
  EXIT;  -- Exit the loop if you only want the first result.
END LOOP;

答案 3 :(得分:6)

使用MAX怎么样? 这样,如果没有找到数据,则将变量设置为NULL,否则设置为最大值 由于您期望0或1值,MAX应该可以使用。

v_column my_table.column%TYPE;
select MAX(column) into v_column from my_table where ...;

答案 4 :(得分:4)

从上面的所有答案中,Björn's answer似乎是最优雅和最短的。我个人经常使用这种方法。 MAX或MIN功能同样可以很好地完成工作。接下来是完整的PL / SQL,只需要指定where子句。

declare v_column my_table.column%TYPE;
begin
    select MIN(column) into v_column from my_table where ...;
    DBMS_OUTPUT.PUT_LINE('v_column=' || v_column);
end;

答案 5 :(得分:3)

我建议使用光标。游标提取始终是单行(除非您使用批量集合),并且游标不会自动抛出no_data_found或too_many_rows异常;虽然您可以在打开后检查游标属性,以确定您是否有一行和多少行。

declare
v_column my_table.column%type;
l_count pls_integer;
cursor my_cursor is
  select count(*) from my_table where ...;

begin
  open my_cursor;
    fetch my_cursor into l_count;
  close my_cursor;

  if l_count = 1 then
    select whse_code into v_column from my_table where ...;
  else
    v_column := null;
  end if;
end;

或者,更简单:

    declare
    v_column my_table.column%type;
    cursor my_cursor is
      select column from my_table where ...;

    begin
      open my_cursor;
        fetch my_cursor into v_column;
        -- Optional IF .. THEN based on FOUND or NOTFOUND
        -- Not really needed if v_column is not set
        if my_cursor%notfound then
          v_column := null;
        end if;
      close my_cursor;
    end;

答案 6 :(得分:2)

我使用这种语法来提高灵活性和速度 -

    begin
    --
    with KLUJ as
    ( select 0 ROES from dual
       union 
      select count(*) from MY_TABLE where rownum = 1
    ) select max(ROES) into has_rows from KLUJ;
    --
    end;

双返回1行,rownum添加0或1行,max()组正好为1.这表示0表示表中没有行,1表示任何其他行数。

我将where子句扩展为按条件计数行,删除rownum以计算满足条件的行,并增加rownum以计算满足条件的行达到限制。

答案 7 :(得分:-3)

COALESCE将始终返回第一个非null结果。通过这样做,您将得到您想要的计数或0:

select coalesce(count(column) ,0) into v_counter from my_table where ...;