1

我正在使用 Oracle apex 并尝试使用自动电子邮件进行练习。理想情况下,场景将是这样的:用户可以通过他的愿望清单向朋友“推荐”游戏。用户通过复选框选择他们想要推荐的游戏,然后选择朋友和电子邮件内容。我为此准备的代码如下:

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;

这仅部分有效。对于一个单一的选择,每个人都可以完美地工作,但是一旦用户选择了多个游戏,那么电子邮件只包含第一个选中的游戏的名称,而不是应该包含的每个游戏。我意识到这与我设置光标的方式有关,但我不完全确定如何在保持 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特定的game_id,因为它可以最大限度地重用——可能还有很多其他地方需要做类似的事情,所以你想编写一次代码并多次使用它。将 in 放入匿名 PL/SQL 块中的循环是完全合法的SELECT INTO,最好将该代码分解为函数。
  • 假设您使用的是最新版本的 APEX,您应该使用该apex_mail软件包而不是旧htmldb_mail软件包。两者之间应该没有任何功能差异,但 HTML DB 是许多版本之前 Oracle APEX 的旧名称,因此逐步淘汰旧包名称的使用是个好主意。
于 2012-07-05T21:18:45.703 回答