1

私はOracleapexを使用しており、自動メールで練習しようとしています。理想的には、これがシナリオの流れです。ユーザーは、ウィッシュリストを介して友達にゲームを「推奨」できます。ユーザーは、チェックボックスを使用して推奨するゲームを選択し、次に友達と電子メールのコンテンツを選択します。このために私が用意しているコードは次のとおりです。

DECLARE
content VARCHAR2(4000) := :P4_EMAIL ||  'Here are the game(s):';
game VARCHAR2(100);
i    NUMBER := 1;

/*Declare the cursor and it's query */
cursor CURSOR IS
    SELECT name
    from gs_games
    where game_id = APEX_APPLICATION.G_F01(i)
    FOR UPDATE;

BEGIN
FOR i in 1..APEX_APPLICATION.G_F01.count
LOOP
OPEN cursor;
FETCH cursor INTO game;
CLOSE cursor;
END LOOP;
htmldb_mail.Send(p_to   => :P4_FRIENDS,
                 p_from => 'gametracker@gametracker.com',
                 p_subj => 'Game recommendations from ' || :F56_USER_NAME,
                 p_body => content || ' ' || game);
END;

これは部分的にしか機能しません。1回の選択で全員が完璧に機能しますが、ユーザーが複数のゲームを選択すると、メールには、すべてのゲームではなく、チェックオフされた最初のゲームの名前のみが含まれます。これは、カーソルを設定する方法に関係していることはわかっていますが、forループをアクティブにしたまま、どのように使用できるかは完全にはわかりません。誰かアイデアはありますか?ありがとうございました。

4

1 に答える 1

2

当面の問題は、カーソルからローカル変数に次の行をフェッチするたびにgame、その変数の以前の値を上書きしていることです。カーソルからすべての行をフェッチgameすると、最後に処理した行の値が得られます。

電子メールにゲーム名のコンマ区切りリストを含めたいと仮定すると、次のようにすることができます

-- You probably want to create this function inside of a package that provides other methods
-- for interacting with games
CREATE OR REPLACE FUNCTION get_game_name( p_game_id IN gs_games.game_id%type )
  RETURN gs_games.name%type
IS
  l_name gs_games.name%type;
BEGIN
  SELECT name
    INTO l_name
    FROM gs_games
   WHERE game_id = p_game_id;

  RETURN l_name;
END get_game_name;

DECLARE
  l_content   VARCHAR2(4000) := :P4_EMAIL ||  'Here are the game(s):';
  l_game_list VARCHAR2(100);
BEGIN
  FOR i in 1..APEX_APPLICATION.G_F01.count
  LOOP 
    l_game_list := l_game_list || ', ' || get_game_name( APEX_APPLICATION.G_F01(i) );
  END LOOP;
  l_game_list := LTRIM( ', ' );

  apex_mail.send( p_to   => :P4_FRIENDS,
                  p_from => 'gametracker@gametracker.com',
                  p_subj => 'Game recommendations from ' || :F56_USER_NAME,
                  p_body => l_content || ' ' || l_game_list);
END;

スタイルに関するいくつかの注意事項

  • カーソルに名前を付けるのCURSORは問題があり、絶対に避けるべきです。カーソルを宣言する必要がある場合は、意味のある名前を付ける必要があります。
  • ローカル変数は、通常、テーブル内の列の名前と区別するような方法で名前を付ける必要があります (私の場合、l_ローカル変数にはプレフィックスp_を使用し、パラメーターにはプレフィックスを使用しますが、有効な規則は多数あります。これは重要です。 PL/SQL SQL ステートメントの識別子は、最初にテーブル内の列の名前を使用して解決され、次にローカル変数を使用して解決されるためです。どちらを使用しているかを明確にするための規則はありません。
  • 単一行のデータを選択するためにカーソルを使用したくない場合。正確に 1 行を返す必要があることがわかっているクエリがある場合は、SELECT INTO.
  • name再利用を最大化するため、特定の for を取得する別の関数を作成しましたgame_id。同様のことを行う必要がある場所が他にもたくさんある可能性が高いため、そのコードを一度記述して何度も使用する必要があります。を無名 PL/SQL ブロックのループに入れることは完全に合法でありSELECT INTO、そのコードを関数に分解することが望ましいでしょう。
  • apex_mail漠然と最近のバージョンの APEX を使用していると仮定すると、古いパッケージではなく、このパッケージを使用する必要がありhtmldb_mailます。この 2 つの間に機能上の違いはないはずですが、HTML DB はかなり前のリリースで Oracle APEX の古い名前だったので、古いパッケージ名の使用を段階的に廃止することをお勧めします。
于 2012-07-05T21:18:45.703 に答える