web-dev-qa-db-ja.com

結果がnullになる可能性があるときにPL / SQLの変数を選択する方法は?

クエリが何も返さない可能性があることを考慮して、クエリを一度実行して変数を選択する方法はありますか?その場合、変数は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行をためらっています。

65
Sapience

変数を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;
107
Adam Paynter

私はそれが古いスレッドであることを知っていますが、まだ答える価値があると思います。

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;
14
jpe

カーソル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;
7
jmc

MAXの使用はどうですか?データが見つからない場合、変数はNULLに設定され、そうでない場合は最大値に設定されます。
値は0または1のいずれかであるため、MAXを使用しても問題ありません。

v_column my_table.column%TYPE;
select MAX(column) into v_column from my_table where ...;
6
Björn

上記のすべての答えから、 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;
4
schemerys

カーソルを使用することをお勧めします。カーソルフェッチは常に(バルクコレクションを使用しない限り)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;
3
Wolf

柔軟性と速度のためにこの構文を使用します-

    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を増やして条件に一致する行を制限までカウントします。

2
user2168235