web-dev-qa-db-ja.com

テーブルに行が存在するかどうかを確認する適切な方法[pl / sqlブロック]

私は昨日いくつかのタスクを書いていましたが、pl/sqlを使用しているときにテーブルに行が存在するかどうかを確認することについて適切で受け入れられた方法がわからないことに気付きました。

例のためにテーブルを使用しましょう

PERSON(ID, Name); 

明らかに私はできない(秘密の方法がない限り)のようなもの:

BEGIN 
  IF EXISTS SELECT id FROM person WHERE ID = 10; 
    -- do things when exists
  ELSE
    -- do things when doesn't exist
  END IF;
END;

したがって、私の標準的な解決方法は次のとおりです。

DECLARE
  tmp NUMBER;
BEGIN 
  SELECT id INTO tmp FROM person WHERE id = 10; 
  --do things when record exists
EXCEPTION
  WHEN no_data_found THEN
  --do things when record doesn't exist
END; 

しかし、それを行う方法が受け入れられているかどうか、またはチェックするより良い方法があるかどうかはわかりませんが、誰かが私と彼らの知恵を共有できるかどうか本当に感謝します:)

乾杯。

37
devBem

通常のコードを例外ブロックにプッシュしません。条件を満たす行が存在するかどうかを確認し、そこから続行します。

declare
  any_rows_found number;
begin
  select count(*)
  into   any_rows_found
  from   my_table
  where  rownum = 1 and
         ... other conditions ...

  if any_rows_found = 1 then
    ...
  else
    ...
  end if;
62
David Aldridge

テーブルに行が存在するかどうかを確認するために使用されるスタンドアロンSELECTを備えたIMOコードは、データベースを適切に活用していません。あなたの例では、ハードコードされたID値を持っていますが、それはアプリが「現実の世界」で動作する方法ではありません(少なくともmy worldではそうではありません-あなたは異なるかもしれません:-)。典型的なアプリでは、カーソルを使用してデータを検索します。つまり、請求書データを参照し、顧客が存在するかどうかを知る必要があるアプリがあるとします。アプリの本体は次のようになります

FOR aRow IN (SELECT * FROM INVOICES WHERE DUE_DATE < TRUNC(SYSDATE)-60)
LOOP
  -- do something here
END LOOP;

-- do something hereで、顧客が存在するかどうかを確認し、そうでない場合はエラーメッセージを出力します。

これを行う1つの方法は、次のように、ある種のシングルトンSELECTを配置することです。

-- Check to see if the customer exists in PERSON

BEGIN
  SELECT 'TRUE'
    INTO strCustomer_exists
    FROM PERSON
    WHERE PERSON_ID = aRow.CUSTOMER_ID;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    strCustomer_exists := 'FALSE';
END;

IF strCustomer_exists = 'FALSE' THEN
  DBMS_OUTPUT.PUT_LINE('Customer does not exist!');
END IF;

しかし、IMOは比較的遅く、エラーが発生しやすいです。これを行うIMO a Better Way(tm)は、メインカーソルに組み込むことです。

FOR aRow IN (SELECT i.*, p.ID AS PERSON_ID
               FROM INVOICES i
               LEFT OUTER JOIN PERSON p
                 ON (p.ID = i.CUSTOMER_PERSON_ID)
               WHERE DUE_DATA < TRUNC(SYSDATE)-60)
LOOP
  -- Check to see if the customer exists in PERSON

  IF aRow.PERSON_ID IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('Customer does not exist!');
  END IF;
END LOOP;

このコードは、PERSON.IDがPERSONのPRIMARY KEYとして宣言されている(または少なくともNOT NULLである)ことを前提としています。ロジックは、PERSONテーブルがクエリに外部結合され、PERSON_IDがNULLになった場合、PERSON.IDには値が必要であるため(つまり、少なくともNOTヌル)。

共有してお楽しみください。

8
Bob Jarvis

この猫の皮をむく多くの方法。各テーブルのパッケージに簡単な関数を配置します...

function exists( id_in in yourTable.id%type ) return boolean is
  res boolean := false;
begin
  for c1 in ( select 1 from yourTable where id = id_in and rownum = 1 ) loop
    res := true;
    exit; -- only care about one record, so exit.
  end loop;
  return( res );
end exists;

小切手を本当にきれいにします...

IF pkg.exists(someId) THEN
...
ELSE
...
END IF;
6
gfrobenius
select nvl(max(1), 0) from mytable;

このステートメントは、行がない場合は0、そのテーブルに少なくとも1つの行がある場合は1になります。 select count(*)を実行するよりもはるかに高速です。オプティマイザーは、質問に答えるために1行のみをフェッチする必要があることを「認識」します。

以下に、(冗長な)小さな例を示します。

declare
  YES constant      signtype := 1;
  NO  constant      signtype := 0;
  v_table_has_rows  signtype;
begin

  select nvl(max(YES), NO)
    into v_table_has_rows
    from mytable -- where ...
  ;

  if v_table_has_rows = YES then
    DBMS_OUTPUT.PUT_LINE ('mytable has at least one row');
  end if;

end;
4
Andreas Wismann
select max( 1 )
  into my_if_has_data
  from MY_TABLE    X
 where X.my_field   = my_condition
   and rownum       = 1;

すべてのレコードを反復処理していません。

MY_TABLEにデータがない場合、my_if_has_dataはnullに設定されます。

0
Robert Tebiev

明示カーソルを使用している場合、次のようになります。

DECLARE
   CURSOR get_id IS 
    SELECT id 
      FROM person 
      WHERE id = 10;

  id_value_ person.id%ROWTYPE;
BEGIN 
   OPEN get_id;
   FETCH get_id INTO id_value_;

   IF (get_id%FOUND) THEN
     DBMS_OUTPUT.PUT_LINE('Record Found.');
   ELSE
     DBMS_OUTPUT.PUT_LINE('Record Not Found.');
   END IF;
   CLOSE get_id;

EXCEPTION
  WHEN no_data_found THEN
  --do things when record doesn't exist
END;
0
Dinidu Hewage
Select 'YOU WILL SEE ME' as ANSWER from dual
where exists (select 1 from dual where 1 = 1);

Select 'YOU CAN NOT SEE ME' as ANSWER from dual
where exists (select 1 from dual where 1 = 0);

Select 'YOU WILL SEE ME, TOO' as ANSWER from dual
where not exists (select 1 from dual where 1 = 0);
0
Mohsen Heydari