SAS 宏传递 SQL 或要在宏中使用的代码
SAS macro passing SQL or code to use in macro
我对 SAS 宏编程比较陌生,我主要用它来制作我的代码 'cleaner' 并避免重复代码中的错误。
我进行了一些谷歌搜索,但没有找到简单的方法。
我首先有 2 个问题 - 如何将列列表传递给宏?
我想让宏在通用代码中看起来像这样:
proc sql;
create table &usefulTable as
%DoStuff('col1, col3, col9', 'col1 = 12 or (col2 between 1 and 3)')
;
基本上我将列值作为第一个参数传递,将 where 子句作为第二个参数传递。
是否可以使宏 what 将通过第一个参数作为列名并将第二个参数用作 where 子句的一部分?
%MACRO DoStuff(col, cond);
select
&col separated by ',' ,
'source1' as source
from &someNiceTable
where &cond
union
select
&col separated by ',' ,
'source2' as source
from &someNiceOtherTable
where &cond
%mend;
以上是显示我打算执行的类似功能的示例基本宏,在本例中为 2 table 的并集,同时添加新列,从 table 中定义的内容被设置为记录。基本上总是对几个 table 应用相同的条件,然后它们将与 union 连接并添加一个额外的列。
如果能对此有所了解就好了。
老实说,我面临的最大问题是传递 were 变量,因为我可以在宏中将列名用作硬编码值,但问题在于 where 子句,因为它经常更改。
你走在正确的轨道上。您在引用这些参数时部分正确,因为第一个参数(列列表)将被解释为 3 个单独的参数,而另一个参数(where 条件)将被解释为名为 col1
的关键字参数。但是,这需要您在宏定义中 dequote
这些参数。一种更简单的方法是在宏调用中使用 %str()
。
您在 proc sql
中对 separated by
的使用也不正确。这与 into
语句一起使用,将 select
语句中的值存储到宏变量中。
您的宏应该如下所示:
%MACRO DoStuff(col, cond);
select
&col,
'source1' as source
from &someNiceTable
where &cond
union
select
&col,
'source2' as source
from &someNiceOtherTable
where &cond
%mend;
调用应该是这样的:
proc sql;
create table &usefulTable as
%DoStuff(%str(col1, col3, col9), %str(col1 = 12 or (col2 between 1 and 3)))
;
quit;
如果您将值作为带引号的字符串传递并希望在不带引号的情况下使用它们,您可以使用 %SYSFUNC()
宏函数调用 DEQUOTE()
函数。
%MACRO DoStuff(col, cond);
select %sysfunc(dequote(&col))
, 'source1' as source
from &someNiceTable
where %sysfunc(dequote(&cond))
;
%mend;
请注意,这还将处理删除您可能使用的任何宏引号而不是文字引号字符来保护您嵌入的逗号。
请注意,对于您的 COND 变量,您可以在条件周围添加 ()
而不是引号或宏引号,以防止宏调用混淆。
因此您的通话可能类似于以下之一:
%DoStuff(col='col1, col3, col9',cond=(col1 = 12 or (col2 between 1 and 3)))
%DoStuff(col=%str(col1, col3, col9),cond=(col1 = 12 or (col2 between 1 and 3)))
我发现传递变量列表时用空格代替逗号要好得多。这样它们就可以直接用于普通的 SAS 语句中。只有 SQL 提出了使用逗号作为分隔符的恼人要求。所以让宏代码加上逗号,这样宏的用户就不用担心添加了。
%macro mymac(dsn,varlist);
%local sqllist;
%let sqllist=%sysfunc(translate(%sysfunc(compbl(&varlist)),%str(,),%str( )));
proc print data=&dsn ;
var &varlist ;
run;
proc sql ;
select &sqllist from &dsn ;
quit;
%mend mymac ;
您还可以使用其他字符(例如 |
或 ^
)作为值列表中的分隔符。
%do i=1 %to %sysfunc(countw(&list,|));
%let word=%scan(&list,&i,|);
...
%end;
我对 SAS 宏编程比较陌生,我主要用它来制作我的代码 'cleaner' 并避免重复代码中的错误。
我进行了一些谷歌搜索,但没有找到简单的方法。
我首先有 2 个问题 - 如何将列列表传递给宏?
我想让宏在通用代码中看起来像这样:
proc sql;
create table &usefulTable as
%DoStuff('col1, col3, col9', 'col1 = 12 or (col2 between 1 and 3)')
;
基本上我将列值作为第一个参数传递,将 where 子句作为第二个参数传递。
是否可以使宏 what 将通过第一个参数作为列名并将第二个参数用作 where 子句的一部分?
%MACRO DoStuff(col, cond);
select
&col separated by ',' ,
'source1' as source
from &someNiceTable
where &cond
union
select
&col separated by ',' ,
'source2' as source
from &someNiceOtherTable
where &cond
%mend;
以上是显示我打算执行的类似功能的示例基本宏,在本例中为 2 table 的并集,同时添加新列,从 table 中定义的内容被设置为记录。基本上总是对几个 table 应用相同的条件,然后它们将与 union 连接并添加一个额外的列。
如果能对此有所了解就好了。
老实说,我面临的最大问题是传递 were 变量,因为我可以在宏中将列名用作硬编码值,但问题在于 where 子句,因为它经常更改。
你走在正确的轨道上。您在引用这些参数时部分正确,因为第一个参数(列列表)将被解释为 3 个单独的参数,而另一个参数(where 条件)将被解释为名为 col1
的关键字参数。但是,这需要您在宏定义中 dequote
这些参数。一种更简单的方法是在宏调用中使用 %str()
。
您在 proc sql
中对 separated by
的使用也不正确。这与 into
语句一起使用,将 select
语句中的值存储到宏变量中。
您的宏应该如下所示:
%MACRO DoStuff(col, cond);
select
&col,
'source1' as source
from &someNiceTable
where &cond
union
select
&col,
'source2' as source
from &someNiceOtherTable
where &cond
%mend;
调用应该是这样的:
proc sql;
create table &usefulTable as
%DoStuff(%str(col1, col3, col9), %str(col1 = 12 or (col2 between 1 and 3)))
;
quit;
如果您将值作为带引号的字符串传递并希望在不带引号的情况下使用它们,您可以使用 %SYSFUNC()
宏函数调用 DEQUOTE()
函数。
%MACRO DoStuff(col, cond);
select %sysfunc(dequote(&col))
, 'source1' as source
from &someNiceTable
where %sysfunc(dequote(&cond))
;
%mend;
请注意,这还将处理删除您可能使用的任何宏引号而不是文字引号字符来保护您嵌入的逗号。
请注意,对于您的 COND 变量,您可以在条件周围添加 ()
而不是引号或宏引号,以防止宏调用混淆。
因此您的通话可能类似于以下之一:
%DoStuff(col='col1, col3, col9',cond=(col1 = 12 or (col2 between 1 and 3)))
%DoStuff(col=%str(col1, col3, col9),cond=(col1 = 12 or (col2 between 1 and 3)))
我发现传递变量列表时用空格代替逗号要好得多。这样它们就可以直接用于普通的 SAS 语句中。只有 SQL 提出了使用逗号作为分隔符的恼人要求。所以让宏代码加上逗号,这样宏的用户就不用担心添加了。
%macro mymac(dsn,varlist);
%local sqllist;
%let sqllist=%sysfunc(translate(%sysfunc(compbl(&varlist)),%str(,),%str( )));
proc print data=&dsn ;
var &varlist ;
run;
proc sql ;
select &sqllist from &dsn ;
quit;
%mend mymac ;
您还可以使用其他字符(例如 |
或 ^
)作为值列表中的分隔符。
%do i=1 %to %sysfunc(countw(&list,|));
%let word=%scan(&list,&i,|);
...
%end;