SAS - 替换包含分号的

时间:2017-11-02 03:18:22

标签: variables sas substring

我需要能够在Aginity Workbench和SAS之间复制粘贴一个包含变量的长SQL脚本。为了简化这一点,我将SQL查询存储在一个宏变量中,如下所示: (注意Netezza样式变量)

%let myQuery = %str(
                      DROP TABLE this;
                      SELECT *
                      INTO SomeTable
                      FROM OtherTable
                      WHERE field = ${myVariable};
                      UPDATE TABLE foo
                      SET x = 1
                      WHERE
                          field = ${anotherVariable};
                    );

当我的SAS程序运行时,我需要它将 $ {netezzaVariables} 替换为前面在流程流中确定的其他宏变量中的文本。到目前为止,我还没能成功替换此宏变量中的文本,我怀疑分号是否会导致问题。

这是我在下面尝试做的事情:

%let formattedText = %sysfunc(tranwrd(&myQuery,'${myVariable}','replacementText'));

该日志显示:

NOTE: Line generated by the macro function "SYSFUNC".
DROP TABLE this;
! SELECT <the rest of the query is printed to console here>

我没有继续编写上面的其余日志,因为错误出现在单词SELECT上,下面有一条红线。在这条红线下方是文字:

  

ERROR 180-322:声明无效或使用不正确。

事实上,如果我继续滚动日志,查询中分号后面的每个第一组字符都会用相同的错误代码加下划线。 这让我相信SAS在SELECT之前拿了分号,用它来终止我正在做的事情,现在认为这个分号后面的文字在开放代码中出来了。

总之,我需要知道如何在宏变量中替换子字符串,该变量的值是包含分号的大字符串。

提前致谢!

3 个答案:

答案 0 :(得分:0)

在使用%sysfunc()字符串函数时,您不需要使用引号。在这种情况下,我认为%qsysfunc是您正在寻找的:

%let myQuery = %str(
                      DROP TABLE this;
                      SELECT *
                      INTO SomeTable
                      FROM OtherTable
                      WHERE field = ${myVariable};
                      UPDATE TABLE foo
                      SET x = 1
                      WHERE
                          field = ${anotherVariable};
                    );
%put &myQuery;

%let formattedText = %qsysfunc(tranwrd(&myQuery,${myVariable},replacementText));
%put &formattedText;

答案 1 :(得分:0)

不是最优雅的解决方案,但它可以完成任务:

%let myQuery = %str(
                      DROP TABLE this;
                      SELECT *
                      INTO SomeTable
                      FROM OtherTable
                      WHERE field = ${myVariable};
                      UPDATE TABLE foo
                      SET x = 1
                      WHERE
                          field = ${anotherVariable};
                    );
data _null_;
call symput('formattedtext',tranwrd("%quote(%superq(myquery))","${myVariable}","replacementText"));
run;

%put %superq(formattedText);

可能有一种方法只使用宏功能,但我无法使用它。

对于您的特定示例,call symput可能已简化为

call symput('formattedtext',tranwrd("&myquery","${myVariable}","replacementText"));

但如果您的查询包含双引号,则会失败,而我上面写的方式则支持。

答案 2 :(得分:0)

约书亚:

如果你的模板&#39;是通用解析器很有用。表达式有很多参数。注意:模板与参数化查询不同,可能更危险。

如果没有解析器,您需要为每个参数编写TRANWRD。

考虑这个宏,假设模板包含由$ { macro-var }指定的参数,并且参数被宏变量值替换。还假设没有以下划线(_)开头的参数可能会与宏内部变量发生冲突。

%macro resolver(_template);
  %local _result;
  %local _tokenRx;
  %local _start _stop _position _length _token _macrovar _guard;

  %let _tokenRx = %sysfunc(prxparse(m/\${([^}]+)}/));
/*%put &=_tokenRx;*/

  %let _guard = 0;
  %let _start = 1;
  %let _stop = %length(&_template);
  %let _position = 0;
  %let _length = 0;

  %let _result = &_template;

  %syscall prxnext(_tokenRx, _start, _stop, _template, _position, _length);

  %do %while (&_position > 0);
/*  %put &=_start &=_stop &=_position &=_length; */
    %let _token = %qsubstr(&_template,&_position,&_length);
    %let _macrovar = %substr(&_token,3,%eval(%length(&_token)-3));

/*
    %put &=_token;
    %put &=_macrovar;
*/
    %if %symexist(&_macrovar) %then %do;
      %let _result = %qsysfunc(tranwrd(&_result,&_token,&&&_macrovar));
    %end;

    %syscall prxnext(_tokenRx, _start, _stop, _template, _position, _length);

    %let _guard = %eval (&_guard+1);
    %if &_guard > 1000 %then %let _position = 0;
  %end;

  %syscall prxfree(_tokenRx);

  %superq(_result)
%mend;

以下是应用于模板化SQL查询的解析器(已调整为Proc SQL)。

%let myQuery = %str(

    DROP TABLE this
;
    INSERT INTO SomeTable /* sas insert syntax */
    SELECT * FROM OtherTable
    WHERE ${field} = ${target}
;
    UPDATE foo
    SET x = 1
    WHERE
        field = ${anotherVariable}
;
);


%let field = name;
%let target = 'Jane';
%let myVariable = XYZ;
%let anotherVariable = 'John';

%put %resolver (%superq(myQuery));

proc sql;
  create table this (id int);
  create table SomeTable like sashelp.class;
  create table OtherTable as select * from sashelp.class;
  create table foo as select name as field, 0 as x from sashelp.class;

  %unquote(%resolver(%superq(myQUery)))
quit;