Select 当结果可能为空时,如何选择PL/SQL中的变量?

Select 当结果可能为空时,如何选择PL/SQL中的变量?,select,plsql,Select,Plsql,考虑到查询可能不返回任何内容,那么在这种情况下,变量应该为null。有没有办法只运行一次查询来选择变量 目前,我无法直接在变量中执行选择,因为如果查询不返回任何内容,PL/SQL将抱怨变量未设置。我只能运行两次查询,第一次执行计数,如果计数为零,则将变量设置为null,如果计数为1,则选择变量 因此,代码如下所示: v_列我的_表。列%TYPE; v_计数器编号; 从my_表中选择计数(列)到v_计数器,其中。。。; 如果(v_计数器=0),则 v_列:=null; elsif(v_计数器=1)

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

目前,我无法直接在变量中执行
选择,因为如果查询不返回任何内容,PL/SQL将抱怨变量未设置。我只能运行两次查询,第一次执行计数,如果计数为零,则将变量设置为null,如果计数为1,则选择变量

因此,代码如下所示:

v_列我的_表。列%TYPE;
v_计数器编号;
从my_表中选择计数(列)到v_计数器,其中。。。;
如果(v_计数器=0),则
v_列:=null;
elsif(v_计数器=1)则
从my_表中选择列进入v_列,其中。。。;
如果结束;
谢谢

更新:
我没有使用exception的原因是,在分配
v_列
之后,我仍然有一些以下逻辑,并且我必须在exception部分使用
goto
,以跳回以下代码。我有点犹豫
goto
行。

您只需将变量设置为
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;

我建议使用游标。游标获取总是一行(除非您使用大容量集合),并且游标不会自动抛出未找到数据或太多行异常;尽管您可以在打开游标属性后检查该属性,以确定是否有行以及有多少行

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;

我使用这种语法是为了灵活性和速度-

    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;
Dual返回1行,rownum添加0或1行,max()组正好为1。对于表中没有任何行,该值为0;对于任何其他行数,该值为1

我扩展where子句以按条件计数行,删除rownum以计数满足条件的行,并增加rownum以计数满足条件的行,直到达到一个限制

使用A是我最喜欢的方法

它比使用显式游标更安全,因为您不需要记住关闭它,所以不会“泄漏”游标。

您不需要“进入”变量,不需要“获取”,不需要捕获和处理“未找到数据”异常

试试看,你再也回不去了

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;

COALESCE
将始终返回第一个非空结果。通过执行此操作,您将获得所需的计数或0:

select coalesce(count(column) ,0) into v_counter from my_table where ...;
用MAX怎么样? 这样,如果找不到数据,变量将设置为NULL,否则为最大值。
因为您期望0或1值,所以MAX应该可以使用

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

我知道这是一条古老的线索,但我仍然认为回答它是值得的

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;

从以上所有答案来看,似乎是最优雅、最简短的。我个人多次使用这种方法。最大或最小功能将同样很好地完成这项工作。下面是完整的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;

@Adam,我没有使用exception的原因是在分配了
v_列
之后,我仍然有一些下面的逻辑,我必须在exception部分使用“goto”跳回下面的代码。我有点犹豫
goto
行。@Sapience,这不是问题,只需将逻辑放在这个嵌套块的末尾。@Shannon:谢谢您的编辑。我自然会使用匿名PL/SQL块,所以我没有意识到这是不明确的。谢谢你的回复。但我试图避免的是对同一where子句运行两次查询,第一次是判断是否存在一个条件,第二次是将现有记录提取到一个变量。@sapicence:Gotcha,我忽略了你的第一句话。在这种情况下,使用cursor属性使这变得非常简单(我建议的第二个选项)。只需将实际查询写入游标(no
COUNT(*)
),打开游标并将结果提取到局部变量中。然后,使用
%FOUND
属性确定所需状态。这样,您只需执行一次查询,不需要异常块,并避免使用
SELECT。。进入
潜在异常。Count将始终返回一个数字,无需合并它。但这个问题并不是真正的计数问题。作者只是为了避免例外情况而获得计数。如果删除聚合函数,则coalesce将无助于避免找不到任何数据,因为可能没有行。此外,像这样将函数包装在列周围通常会跳过可能已使用的任何索引,因为编译器无法判断该函数是否会更改列值,从而使其在索引中无法查找,所以它根本不寻找任何索引。(您可以创建一个基于函数的索引来提供帮助,但实际上,谁知道该怎么做呢?)。它很好用。为了简单起见,我跳过了开始和结束部分。@Miki:我添加了一个示例来说明它是PLSQL,并且可以工作。我在这里看到了这种技术:当我将多个列写入变量时,它似乎不起作用。我得到了太多的值。谢谢你的评论!没错,它只适用于1列,因为标量子查询只能返回1个值。我希望有人能改变这一点……我利用这一技巧创建了一个漂亮的select查询。谢谢:(从dual中选择round(round(round(在('2018年5月30日,'c.column_date')之间的月份),0)/12,1)作为参数,当查询返回多行时也可以使用