【问题标题】:Name/Title of the macro as a variable inside a macro SAS宏的名称/标题作为宏 SAS 中的变量
【发布时间】:2015-06-18 15:02:00
【问题描述】:

我正在尝试使用 PARMBUFF 宏来重复具有 20 个不同客户端定义的数据步骤(下面的一个示例)。

DATA _NULL_;
%GLOBAL bank1;
%LET bank1 = O.OWNER LIKE 'XXXXX%';
RUN;

数据步骤将创建由上面创建的客户端宏变量定义的单独表。

%MACRO CLIENTBUILD/PARMBUFF; 
%LET N=%SYSFUNC(COUNTW(&SYSPBUFF,%STR(,)));
%DO I=1 %TO &N;
  %LET CLIENT=%SCAN(%QSYSFUNC(COMPRESS(%BQUOTE(&SYSPBUFF),%STR(%(%)))),&I,%STR(,));
CREATE TABLE CLIENT AS
SELECT DISTINCT C.DATE,
            C.TIME,
            C.RELEASE,
            C.TASK
FROM CALLS C
INNER JOIN OWN_GRNT O ON SUBSTR(C.TASK,1,9)= O.TASK 
AND    &CLIENT
;
%END;
%MEND;

我想使用宏的名称(字符串)创建此表……但在引用宏的字符串以获取表的名称时遇到问题。 我尝试使用

%MACRO CLIENTBUILD/PARMBUFF; 
%LET N=%SYSFUNC(COUNTW(&SYSPBUFF,%STR(,)));
%DO I=1 %TO &N;
  %LET CLIENT=%SCAN(%QSYSFUNC(COMPRESS(%BQUOTE(&SYSPBUFF),%STR(%(%)))),&I,%STR(,));
CREATE TABLE '&CLIENT' AS
SELECT DISTINCT C.DATE,
                C.TIME,
                C.RELEASE,
                C.TASK
FROM CALLS C
INNER JOIN OWN_GRNT O ON SUBSTR(C.TASK,1,9)= O.TASK 
AND    &CLIENT
;
%END;
%MEND;
Then calling the macro out with – 
PROC SQL;
%CLIENTBUILD(&NCT);
QUIT;

但这会导致错误:

ERROR: The value &CLIENT is not a valid SAS name.`

是否有一种解决方案可以调用依赖于用于定义客户端的宏变量的宏标题?解决后,我想用 .... 创建每个客户端数据集。

Proc SQL; 

%CLIENTBUILD(&bank1,&bank2,&bank3,..........);

QUIT;

【问题讨论】:

  • 删除 &CLIENT 周围的单引号 -- 如 CREATE TABLE &client AS... 单引号掩盖了 &CLIENT 变量的解析。 SAS 表不能以 & 开头,这是给你的错误。
  • 问题在于它将解决实际的宏定义(O.OWNER LIKE 'XXXXX%'),而不仅仅是名称 - “bank1”...我只希望它在在“WHERE &CLIENT”部分的底部(原始帖子中的错误......改为 AND &CLIENT),并使用字符串(bank1)作为表的名称......
  • 使用宏引用(例如%nrstr)来控制分辨率。如果你想要bank1 而不是&bank1,你会遇到一些困难,因为这不是 SAS 宏变量的工作方式。您需要重新考虑这里的方法 - 特别是,听起来您应该传递两个参数,而不是一个。
  • 接受了这个想法,但在使用两个参数构造 PARMBUFF 时遇到问题...尝试包含一个额外的 "%LET VAR2=%SCAN(%QSYSFUNC(COMPRESS(%BQUOTE(&SYSPBUFF),%STR (%(%)))),&I,%STR(,));"在宏构建中...然后执行为 %CLIENTBUILD(&BANK1,&VAR2);但没有成功。

标签: sas


【解决方案1】:

首先,一个建议。不要以这种方式构建您的应用程序。这是一种非常混乱且危险的方法。您正在使用应该是参数的全局宏变量,并且您正在尝试对这些宏变量名称的列表进行文本解析。

这样写宏:

%macro maketable(table=,where=);
  proc sql;
    create table &table. as 
      ...
      where &where.;
  quit;
%mend maketable;

然后从存储您的 WHERE 子句的数据集中构造对 %maketable 的调用(我假设这不仅仅是开放代码?如果是,请通过 excel 或其他方式将其放入数据集中。)

proc sql;
  select cats('%maketable(table=',tablename,',where=%nrstr(',whereclause,'))'
     into :tablecall separated by ' '
     from my_whereclause;
quit;

然后只需在下一行包含&tablecall.,当您运行它时,您将获得所有表格。

(顺便说一句,您可能甚至不能制作 20 个表,而是制作 1 个具有 20 个变量值的表 - 但您没有解释在此之后您在做什么,所以很难告诉。)


如果您必须这样做,您需要了解宏变量解析的工作原理。请参阅 my answer here 以获得一些解释,或参阅 my SGF paper 了解该主题。 SAS 文档也很好地解释了这一点。

基本上,你需要单独解析你的表名&table来定义表名,然后多次解析它以获得where子句。

这是一个使用 sashelp.class 的示例。

%let abc= age gt 13;
%let def= age lt 13;
%let ghi= age eq 13;
%macro doit/parmbuff;
    %LET N=%SYSFUNC(COUNTW(&SYSPBUFF,%STR(,)));
    %DO I=1 %TO &N;
      %LET CLIENT=%SCAN(%QSYSFUNC(COMPRESS(%BQUOTE(&SYSPBUFF),%STR(%(%)))),&I,%STR(,));
      %PUT &=CLIENT;

      proc sql;
        create table &client. as 
            select * from sashelp.class
            where &&&client.;
      quit;
    %end;
%mend doit;

%doit(abc,def,ghi);

&&&client 将 &client 解析为 abc,然后在此处留下一个 & 符号(因此 &abc) - 然后解析它,因此它将 &abc 解析为其值(where 子句)。

【讨论】:

  • 给你一个检查...在这一切结束时,退后一步并重建(程序和宏结构)是解决方案。至于您关于创建一个包含所有变量的附加数据集的建议……打开了一些灵活性。非常感谢!
【解决方案2】:

对于这种类型的应用程序,您不需要使用 PARMBUFF。只是不要使用逗号作为分隔符。例如,您可以使用空格或 |如下例所示。

%macro doall(list);
  %local i item ;
  %do i=1 %to %sysfunc(countw(&list,|));
    %let item=%scan(&list,&i,|);
    ... process current item ...
  %end;
%mend doall ;
%doall(A|B|C|D);

【讨论】:

    猜你喜欢
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    相关资源
    最近更新 更多