2015-08-06 4 views
3

Я пишу макро переменную, целью которой является создание действующего предложения SQL WHERE, как указано пользователем в приглашениях. Предположим, что мы имеем 3 переменных X, Y, Z и т. Д. Пользователь может указать фильтр для каждой переменной и макропеременной выглядит следующим образом:SAS удаляет указанное слово при его запуске или завершении выражения

a = x eq 1 and y eq 1 and z eq 1; 

, который затем приступил к ИНЕК. Но если пользователь указывает только, скажем,»фильтр для Y это выглядит следующим образом:

a = and y eq 1 and 

И я хотел бы, чтобы это выглядело как:

a = y eq 1 

Вот почему я хотел бы каким-то образом удалить операнд «и», когда он начинает или заканчивает выражение (оно может начать или закончить его несколько раз, например, если мы Фитлер только Z переменной она выглядит):

a = and and and z eq 1 

Я предполагаю, что это можно легко сделать с регули но поскольку я новичок в этом, есть ли кто-нибудь, кто хочет мне помочь? ;)

+0

У вас уже есть хорошие решения. В зависимости от сложности ваших пользователей иногда вы можете просто иметь единственный параметр WHERE и позволить пользователям писать любое выражение, которое они хотят, в качестве значения одного приглашения, а не передавать значения для каждой части выражения. Для опытных пользователей это дает им большую гибкость, конечно, за счет необходимости требовать от них правильного выражения. – Quentin

ответ

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; 
+0

Для записи я думаю, что решение Джо - это путь. Вышеприведенный подход может быть более полезным в более сложных примерах. –

2

Предполагая, что вы делаете это с помощью макропараметров, это проще сделать, предоставив значение по умолчанию.

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

1 является «истинным», поэтому он действует (наряду с «И») в качестве аргумента влево.

Если вы хотите, чтобы передать значения (не полное равенство), то вы можете также сделать это:

%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).

+0

ОК, но теперь пользователь должен указать равенства вместо значений. –

+0

@DirkHorsten Учитывая вопрос, я думаю, что это так и было сделано. Посмотрите на код «ничего не заданного»: он не включает в себя 'x =' ... – Joe

+1

И было бы так же легко, чтобы значение 'x' было значением, а затем по умолчанию было' x = x'. Переменные всегда равны сами по себе [в SAS, а не в sql-сервере, конечно]. – Joe

0

Вы можете использовать малоизвестное выражение «где также». Добавлены выражения «where also», логически равные оператору AND для каждого предложения WHERE, и вы можете использовать «где также» в качестве вашего первого предложения WHERE без каких-либо проблем с вашим кодом.

Если у вас есть макрос так:

%MACRO get_data; 

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

%MEND; 

Вы можете переписать как коснуться:

% MACRO get_data;

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 = ; 
+0

. У вас может быть только одно предложение where, так что теперь пользователь может заполнить только один критерий –

+0

@DirkHorsten Вы можете имеют столько, сколько вам нравится. Я все время использую такой код. Также см. это: http://www.sascommunity.org/wiki/Where_also –

+1

Спасибо, никогда не осознал, что у меня может быть несколько предложений where на шаге данных, но вопрос был о PROC SQL. Там вы не можете. –

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); 
+0

Я был бы осторожен в использовании '% length (& yvalue)' здесь, особенно если это не просто значения, которые вы передаете, но, возможно, выражения - это одно из наиболее вероятных мест для получения вещей, которые не будут работать с этим. http://stackoverflow.com/questions/31686223/testing-for-an-empty-parameter-in-a-sas-macro/31686698#31686698 упоминает превосходную бумагу, которая подробно описывает это. В противном случае это хороший вариант. – Joe

0

Спасибо всем, я уже понял, подобную структуру, @Robert Penridge, но я отвечаю на все ответы :) Спасибо!

PS. Я также не был знаком с ГДЕ ТАКЖЕ - может оказаться полезным в будущем :)

Смежные вопросы