2

我在连接要立即执行的字符串时遇到问题。任何人都知道下面的以下陈述有什么问题。

立即执行 'ALTER SESSION SET smtp_out_server = ''||SMTPServer||''';

select smtpserver into SMTPServer from mytable;

if(SMTPServer is not null)
then
  EXECUTE IMMEDIATE 'ALTER SESSION SET smtp_out_server = ''||SMTPServer||''';
  --*****above does not work, below does work****
  EXECUTE IMMEDIATE 'ALTER SESSION SET smtp_out_server = ''10.1.1.1''';
4

2 回答 2

6

从构建所需字符串的角度来看,您缺少几个单引号。在局部变量之前需要 3 个单引号,在SMTPServer局部变量之后需要 4 个单引号

'ALTER SESSION SET smtp_out_server = ''' || smtpServer || ''''

就个人而言,我会发现在声明模板(使用 q 引用语法,因为它嵌入了单引号),调用replace以替换模板化值,然后调用EXECUTE IMMEDIATE. 它的代码有点多,但通常会使生活更轻松。

l_sql_stmt := q'{ALTER SESSION SET smtp_out_server = '##server##'}';
l_sql_stmt := replace( l_sql_stmt, '##server##', smtpServer );
EXECUTE IMMEDIATE l_sql_stmt;

但是,您确定第二个语句确实有效吗? smtp_out_server不应该在没有数据库重新启动的情况下进行修改。我见过有人说他们已经能够ALTER SYSTEM在运行时成功地修改它,但还没有看到有人尝试用ALTER SESSION. 我会犹豫构建取决于违反文档的行为的代码。如果您需要在运行时控制正在使用的 SMTP 服务器,我强烈建议您使用utl_smtp包而不是utl_mail.

于 2015-07-15T21:26:11.220 回答
0

提供 EXECUTE IMMEDIATE 替换参数的语句并不是很好,因为对于优化器来说,它每次都是完全不同的语句,因此它为每个语句准备另一个执行计划。您应该在 EXECUTE IMMEDIATE 子句中使用绑定。

例子:

DECLARE
  SMTPServer mytable.smtpserver%type;

  l_set_smtpserver_stmt VARCHAR2(600) := q'#ALTER SESSION SET smtp_out_server = ':p_smtp_server'#'

BEGIN
  SELECT smtpserver INTO SMTPServer FROM mytable;

  IF SMTPServer IS NOT NULL THEN
  EXECUTE IMMEDIATE l_set_smtpserver_stmt USING SMTPServer;
  END IF;


  EXCEPTION
    -- handle no_data_found exception since you're using select .. into statement
    WHEN NO_DATA_FOUND THEN
        -- handle exception
    WHEN OTHERS THEN
        -- handle exception
END;
/
于 2015-07-16T10:05:09.497 回答