SAS在启动或结束表达式时删除指定的单词

时间:2015-08-06 13:06:45

标签: regex sas

我正在编写一个宏变量,旨在根据用户在提示中指定生成有效的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 

我想用正则表达式可以轻松完成,但由于我是新手,有人愿意帮我吗? ;)

5 个答案:

答案 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。我也不熟悉其中的地方 - 可能在将来证明有用:)