我正在编写一个宏变量,旨在根据用户在提示中指定生成有效的SQL WHERE子句。假设我们有3个变量X,Y,Z等。用户可以为每个变量和宏变量指定过滤器,如下所示:
a = x eq 1 and y eq 1 and z eq 1;
然后继续进入WHERE子句。 但是,如果用户仅指定,请说'过滤Y看起来像:
a = and y eq 1 and
我希望它看起来像:
a = y eq 1
这就是为什么我想以某种方式删除操作数'AND',当它开始或结束表达式时(它可能多次开始或结束,例如,如果我们只有fitler,它只是Z变量):
a = and and and z eq 1
我想用正则表达式可以轻松完成,但由于我是新手,有人愿意帮我吗? ;)
答案 0 :(得分:2)
假设您通过宏参数执行此操作,则通过提供默认值更容易实现。
%macro filter(x=1,y=1,z=1);
where &x. and &y. and &z.;
%mend filter;
1是" true",所以它作为左撇子参数(和" AND")一起行动。
如果您只想传递值(而不是完全相等),那么您也可以这样做:
%macro filter(x=x, y=y, z=z);
where x=&x. and y=&y. and z=&z.;
%mend filter;
x=x
在SAS中始终如此,但如果您正在传递给SQL Server或Oracle并且可能具有空值,则这将无效(因为null=null
在SQL Server或Oracle中为false )。
答案 1 :(得分:2)
对@ DirkHorsten技术的轻微修改。这只是以稍微不同的方式组织代码,以便可以更容易地读取SQL语句。在我看来,SQL语句是您希望读者理解的重要代码段(所以让它保持简单!),而where子句的构建只是一个侧面注释。这可能是一种有价值的方法,尤其是当您的SQL语句变得更加复杂时。
方法1,所有过滤器的单个变量:
%macro getMyData(xValue=, yValue=, zValue=);
%local and_filters;
* THE BORING IMPLEMENTATION DETAILS ARE KEPT SEPARATE;
%let and_filters = ;
%if "&xValue" ne "" %then %do;
%let and_filters = &and_filters and sex eq "&xValue";
%end;
%if "&yValue" ne "" %then %do;
%let and_filters = &and_filters and age eq &yValue;
%end;
%if "&zValue" ne "" %then %do;
%let and_filters = &and_filters and height eq &zValue;
%end;
* THE IMPORTANT PIECE OF CODE IS EASY TO READ;
proc sql;
select *
from sashelp.class
where 1 &and_filters
;
quit;
%mend;
方法2,每个过滤器的个别变量:
%macro getMyData(xValue=, yValue=, zValue=);
%local and_sex_filter and_age_filter and_height_filter;
* THE BORING IMPLEMENTATION DETAILS ARE KEPT SEPARATE;
%let and_sex_filter = ;
%let and_age_filter = ;
%let and_height_filter = ;
%if "&xValue" ne "" %then %do;
%let and_sex_filter = and sex eq "&xValue";
%end;
%if "&yValue" ne "" %then %do;
%let and_age_filter = and age eq &yValue;
%end;
%if "&zValue" ne "" %then %do;
%let and_height_filter = and height eq &zValue;
%end;
* THE IMPORTANT PIECE OF CODE IS EASY TO READ;
proc sql;
select *
from sashelp.class
where 1
&and_sex_filter
&and_age_filter
&and_height_filter
;
quit;
%mend;
答案 2 :(得分:1)
%macro getMyData(xValue=, yValue=, zValue=);
proc sql;
select *
from sashelp.class
where
%if %length(&xValue) %then %do;
sex = "&xValue." and
%end;
%if %length(&yValue) %then %do;
age = &yValue. and
%end;
%if %length(&zValue) %then %do;
height >= &zValue. and
%end;
1;
quit;
%mend;
Title 'Females';
%getMyData(xValue=F);
Title '12 year';
%getMyData(yValue=12);
Title 'Large males';
%getMyData(xValue=M, zValue=60);
答案 3 :(得分:0)
您可以使用一个鲜为人知的“where also”表达式。附加“where also”表达式在逻辑上等于每个WHERE子句的AND运算符,并且您可以将“where also”用作第一个WHERE子句,而不会对代码产生任何问题。
如果您有这样的宏:
transform(dt,
ID=make.unique(as.character(ID)), #change the ID column
Outcome=ifelse(duplicated(ID),-9, Outcome)) #change Outcome
你可以改写为:
%MACRO get_data;
%MACRO get_data;
data want;
set have;
where a = x eq 1 and y eq 1 and z eq 1;
RUN;
%MEND;
在测试代码之前,您至少需要初始化宏变量。 你可以这样做:
data want;
set have;
%IF &X ne %THEN
%DO;
where also &x eq 1;
%END;
%IF &Y ne %THEN
%DO;
where also &y eq 1;
%END;
%IF &Z ne %THEN
%DO;
where also &z eq 1;
%END;
RUN;
%MEND;
答案 4 :(得分:0)
谢谢大家, 我已经找到了与@Robert Penridge相似的结构,但是我对所有答案都赞不绝口:)谢谢!
PS。我也不熟悉其中的地方 - 可能在将来证明有用:)