如何在PL / SQL中动态添加内容到电子邮件?

时间:2012-07-05 20:57:07

标签: plsql cursor oracle-apex

我正在使用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;

这只是部分有效。对于单个选择,每个人都可以完美地工作,但是一旦用户选择了多个游戏,那么电子邮件仅包含已检查的第一个游戏的名称,而不是每个游戏应该包含的名称。我意识到这与我设置光标的方式有关,但我并不完全确定如何在保持循环活动的同时使用它。有没有人有任何想法?谢谢。

1 个答案:

答案 0 :(得分: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的{​​{1}},因为这样可以最大限度地重复使用 - 可能还有很多其他地方需要做类似的事情,所以你想写一下代码一次,并多次使用它。将game_id放入匿名PL / SQL块的循环中是完全合法的,最好将该代码分解为函数。
  • 假设您使用的是最近版本的APEX,则应使用SELECT INTO包,而不是旧的apex_mail包。两者之间不应该有任何功能差异,但HTML DB是很多版本之前Oracle APEX的旧名称,所以逐步淘汰旧包名称的使用是个好主意。