クエリが何も返さない可能性があることを考慮して、クエリを一度実行して変数を選択する方法はありますか?その場合、変数はnullでなければなりません.
現時点では、select into
変数を直接実行することはできません。クエリが何も返さない場合、PL/SQLは変数が設定されていないと文句を言うからです。クエリは2回しか実行できません。最初のクエリはカウントを実行し、カウントがゼロの場合は変数を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
行をためらっています。
変数をNULL
に設定することにより、NO_DATA_FOUND
例外を簡単に処理できます。この方法では、必要なクエリは1つだけです。
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;
私はそれが古いスレッドであることを知っていますが、まだ答える価値があると思います。
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;
カーソルFOR LOOPステートメント を使用するのが、これを行うための私のお気に入りの方法です。
明示的なカーソルを使用するよりも安全です。閉じることを覚えておく必要がないため、カーソルを「リーク」することはできません。
「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;
MAXの使用はどうですか?データが見つからない場合、変数はNULLに設定され、そうでない場合は最大値に設定されます。
値は0または1のいずれかであるため、MAXを使用しても問題ありません。
v_column my_table.column%TYPE;
select MAX(column) into v_column from my_table where ...;
上記のすべての答えから、 Björnの答え が最もエレガントで短いようです。私はこのアプローチを何度も使用しました。 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;
カーソルを使用することをお勧めします。カーソルフェッチは常に(バルクコレクションを使用しない限り)1行であり、カーソルは自動的に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;
柔軟性と速度のためにこの構文を使用します-
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を増やして条件に一致する行を制限までカウントします。