SAS宏引用:将等号作为宏参数传递

时间:2015-11-24 20:43:19

标签: sas sas-macro

我正在编写一个宏,在某些时候会调用一些proc SQL代码。我希望用户能够指定任意proc sql选项(例如inobs = 100可能是我的宏的输入参数之一)。

我很难引用一个平等的论证' ='字符。

其中一个问题是我还应该检查宏参数是否为空,如果它不为空,则只将指定的选项添加到sql语句中。

下面是一个不起作用的示例非工作测试并抛出

  

错误:关键字参数INOBS未使用宏定义。

我已经阅读了这个(http://www2.sas.com/proceedings/sugi28/011-28.pdf)和其他SUGI,并尝试了许多可能的引用和调用宏的方法。

如果有人能提供以下功能的工作示例,我们将不胜感激。

var casper = require('casper').create();
casper.start('http://www.waynecountyauditor.org/Reports.aspx?ActiveTab=Sales')
.waitForText("Accept")
.thenClick('#ctl00_ContentPlaceHolder1_btnDisclaimerAccept')
.waitForText("View Sales")
.thenClick('#ctl00_ContentPlaceHolder1_WeeklySales_fvSalesReport_btnViewSales')
.waitForText("Download Sales Report")
.thenClick(x('//*[@id="ctl00_blSearchLinks"]/li[4]/a'))
.wait(1000)
.on('page.resource.received', function(resource) {
console.log('here');
if (resource.stage !== "end") {
    return;
}
if (resource.url.indexOf('results.csv') > -1) {
    this.download(resource.url, 'D:\Jobs\Currency\testing\ExportData.csv');
}

});
casper.run();

3 个答案:

答案 0 :(得分:4)

如果您按如下方式移除%if条件,则应该有效:

%macro pass_parameter_with_equal_sign(table=, sqlOptions=);
    proc sql 
    &sqlOptions.
    /* the semicolon to end the proc sql statement */
    ;
        create table macro_output as 
            select * 
            from have;
    quit;
%mend;

您使用的%if是检查&sqlOptions是否为空白,如果您按原样使用它并不重要,因为它的无条件使用会给出:

proc sql inobs=2; /* in the case of &sqlOptions=inobs=2 */

或者如果没有为&sqlOptions提供任何值,那么您应该看到:

proc sql; /* i.e. no options specified */

所以它应该有或没有参数。

此致 阿米尔。

答案 1 :(得分:3)

Amir的解决方案可能适合您的特定用例。但是为了回答更一般的问题,我们需要查看关于宏观参数测试的开创性论文,Chang Chung的Is This Macro Parameter Blank?

他的例子C8对你来说是正确的,虽然其他一些也可以。

%if %sysevalf(%superq(param)=,boolean) %then ... /* C8 */ 

例如:

%macro test_me(param=);

  %if %sysevalf(%superq(param)=,boolean) %then %put Empty;
  %else %put Not Empty;;
%mend test_me;

%test_me(param=);
%test_me(param=MyParam);
%test_me(param=param=5);

%SUPERQ在这里最有用,因为它避免了解析宏参数。相反,它将它保持为宏参数值 - 完全未解析 - 并允许您以这种方式使用它;所以你没有那种麻烦的等号困扰你的风险。

他的C4(仅使用没有SYSEVALF的SUPERQ)也适用于这种情况,尽管他解释了一些可能有困难的情况。

答案 2 :(得分:1)

啊,这实际上是一个棘手的小问题。问题实际上是由对%trim()%left()的调用引起的。

删除这些导致代码按预期工作(注意我还删除了参数周围的宏引用):

%macro pass_parameter_with_equal_sign(table=, sqlOptions=);
    proc sql 
    %if "&sqlOptions" ne "" %then %do;
        &sqlOptions
    %end;
    /* the semicolon to end the proc sql statement */
    ;
        create table macro_output as 
            select * 
            from &table;
    quit;
%mend;

%pass_parameter_with_equal_sign(table=sashelp.class, sqlOptions= inobs=2);

我们可以重新创建您遇到的问题:

%put %trim(inobs=1);

因为参数正在解析为inobs = 1,并且%trim()没有任何命名参数,所以它正在抛出一个混合物。要正确传入包含“inobs = 1”的字符串,我们可以这样做:

%let param = inobs=1;
%put %trim(%str(&param));

注意:Amir完全删除%if语句的解决方案也是设计这样的代码的最佳方法。我只是提供了有关您遇到此问题的详细信息。

附加说明1 - 为什么不需要%left()%trim

顶部代码段提供与具有"%left(%trim(&sqlOptions.))"的原始代码相同的预期功能。这是因为从宏变量(包括宏参数)中删除了开始和结束空白,除非使用宏引用明确保留它。一个简单的例子就是:

%let param =      lots      of     spaces        ;
%put ***&param***;

给予:

***lots      of     spaces***

您可以看到内部空白被保留,但左右填充消失了。为了保留空格,我们可以简单地使用%str()函数。

%let param = %str(     lots      of     spaces        );
%put ***&param***;

给出:

***     lots      of     spaces        ***

附加说明2 - 使用包含空格的宏

如果您确实在宏变量上有空格,因为它被引用而需要删除,并且您希望使用%left()%trim()这样做,那么事情就会变得有些古怪。我们的变量可以这样创建:

%let param = %str(     inobs = 2        );

你可以看到我们已经用%str()引用了这个值来创建它。这意味着我们现在可以调用其中一个函数而无需再次引用它:

%put %trim(&param);  * ALREADY QUOTED AT CREATION SO THIS WORKS FINE;

但是,如果我们尝试将结果输入%left()函数,我们就会回到原来的问题:

%put %left(%trim(&param));  * OOPS. DOESNT WORK;

现在我猜这里,但我相信这很可能是因为%trim()函数在返回结果之前删除了任何宏引用。有点像这样:

%put %unquote(%trim(&param));

可以通过再次使用%str()重新引用返回的结果来避免这种情况:

%put %left(%str(%trim(&param)));

...或用%nrstr()包装原始参数:

%let param = %str(     inobs = 2        );
%put %left(%trim(%nrstr(&param)));

...或使用%sysfunc()调用datastep函数:

%put %sysfunc(compress(&param));