有没有办法只运行一次查询以选择变量,考虑到查询可能什么都不返回,那么在这种情况下变量应为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
行犹豫不决。
答案 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 ...;