【问题标题】:SAS remove the specified word when it starts or ends the expressionSAS 在开始或结束表达式时删除指定的单词
【发布时间】:2015-08-06 13:06:44
【问题描述】:

我正在编写一个宏变量,旨在生成用户在提示中指定的有效 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”(它可能多次开始或结束它,例如,如果我们只拟合 Z 变量,它看起来像):

a =  and and and z eq 1 

我想用正则表达式可以很容易地完成,但由于我是新手,有没有人愿意帮助我? ;)

【问题讨论】:

  • 您已经有了很好的解决方案。根据用户的复杂程度,有时您可以只使用一个 WHERE 参数,并让用户编写他们想要的任何表达式作为单个提示的值,而不是为表达式的每个部分传递值。对于老练的用户,这为他们提供了更大的灵活性,当然代价是要求他们编写正确的表达式。

标签: regex sas


【解决方案1】:

对@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】:

假设您通过宏参数执行此操作,则通过提供默认值更容易做到这一点。

%macro filter(x=1,y=1,z=1);
  where &x. and &y. and &z.;
%mend filter;

1 为“真”,因此它(与“AND”一起)作为一个被遗漏的参数。

如果您只想传递值(而不是完全相等),那么您也可以这样做:

%macro filter(x=x, y=y, z=z);
  where x=&x. and y=&y. and z=&z.;
%mend filter;

x=x 在 SAS 中始终为 true,但如果您要传递到 SQL Server 或 Oracle 并且可能有空值,这将不起作用(因为 null=null 在 SQL Server 或 Oracle 中为 false)。

【讨论】:

  • 好的,但现在用户必须指定等式而不是值。
  • @DirkHorsten 鉴于这个问题,我认为无论如何都是这样做的。查看“未指定”代码:它不包括 x=...
  • x 作为一个值,然后将x=x 作为默认值同样容易。变量总是等于它们自己[在 SAS 中,当然不是在 sql server 中]。
  • 如果你的x值不是用户手动编码,而是计算出来的怎么办?如果它是存储过程或 SAS EG 程序的可选提示怎么办?
  • ?我不确定你在说什么。我建议包含一个默认值,这样如果不包含它,它将具有一个使其自动为真的值。我看不出这有什么影响。
【解决方案3】:
%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);

【讨论】:

  • 我会小心在这里使用%length(&yvalue),特别是如果它不仅是您传递的值,而且可能是表达式 - 这是最有可能获得无法使用的东西的地方之一. stackoverflow.com/questions/31686223/… 提到了一篇非常详细的优秀论文。否则,这是一个不错的选择。
【解决方案4】:

您可以使用一个鲜为人知的“where also”表达式。为每个 WHERE 子句附加了逻辑上等于 AND 运算符的“where Also”表达式,您可以将“where Also”用作您的第一个 WHERE 子句,而不会对您的代码造成任何问题。

如果你有这样的宏:

%MACRO get_data;

data want;
    set have;
    where a = x eq 1 and y eq 1 and z eq 1;
RUN;

%MEND;

你可以改写成这样的:

%MACRO 获取数据;

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;

在测试代码之前,您至少需要初始化宏变量。 你可以这样做:

%IF %symexist(&Z)=0 %THEN %LET Z = ;

【讨论】:

  • 你只能有一个where子句,所以现在用户只能填写一个条件
  • @DirkHorsten 您可以拥有任意数量的。我一直使用这样的代码。另请参阅:sascommunity.org/wiki/Where_also
  • 谢谢,我从来没有意识到我可以在一个数据步骤中有多个 where 子句,但问题是关于 PROC SQL。那里你不能。
  • 对 - 不幸的是,这在 PROC SQL 中不起作用,这正是我立即想到的,否则......
  • 是的,当我第一次看到 Don Henderson 在某处指出它时,WHERE 也改变了我的生活。使 DATA STEP / PROC 的生活变得更容易(但不是 PROC SQL,遗憾的是)。
【解决方案5】:

谢谢大家, 我已经想出了与@Robert Penridge 类似的结构,但我感谢所有答案:) 谢谢!

PS。我也不熟悉 WHERE ALSO - 将来可能会很有用:)

【讨论】:

    猜你喜欢
    • 2016-02-06
    • 2018-04-13
    • 2021-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多