I have a SAS macro below that is not working--- this snippet returns no values because the where statement doesn't work. Anyone have any ideas? I tried adding %str but that didn't work either.
%macro refreshments(beverage_type=);
proc sql;
select
*
where drink_type = '&beverage_type.'
;
quit;
%mend
%refreshments(Sprite);
Thanks.
Macro variables will not resolve in single quotes. You are also missing the FROM clause, and the macro parameter was being provided as positional (instead of name=value pair). Try the following:
%macro refreshments(beverage_type=);
proc sql;
select *
from YOURTABLE
where drink_type = "&beverage_type";
%mend;
%refreshments(beverage_type=Sprite);
Related
I am trying to create a macro where one of the parameters is a list. My macro includes a proc sql with a where statement that has something like this:
Where Name in ('sarah','ben','adam')
I tried doing something like this:
%MACRO DATA_PULL (name=);
PROC SQL;
SELECT
FROM
Where Name in &name
;
QUIT;
%MEND DATA_PULL;
%DATA_PULL (Name=('sarah','ben','adam'))
but it doesn't work :(
any help appreciated
The SAS in operator does not require commas. This is valid syntax:
where Name in ('sarah' 'ben' 'adam')
so you could have macro invocation with
, names = ('sarah' 'ben' 'adam')
You can also pass commas in a macro parameter by properly quoting the value or value portion. In this case %str can be used.
, names = (%str('sarah','ben','adam'))
If you place the %str outside the in list parenthesis you may also want to escape the parenthesis within the %str
Some example invocations
%macro x(names=);
proc sql;
create table want as
select * from sashelp.class
where name in &names
;
%mend;
%x(names=('Jane' 'James'))
%x(names=(%str('Jane', 'James')))
%x(names=%str(%('Jane', 'James'%)))
you need to using macro quoting functions.
%MACRO DATA_PULL (name=);
PROC SQL;
SELECT *
FROM sashelp.class
Where Name in &name
;
QUIT;
%MEND DATA_PULL;
%DATA_PULL (Name = %str(('Alfred', 'Alice', 'Barbara')))
Trying to put commas in the value of the macro variable is the issue since comma is used to mark the transition between parameter values in the macro call.
What you posted is actually one way to allow the inclusion of commas in the value of a macro parameter. By enclosing the value inside or () the SAS compiler will know that the commas do not mark the start of new parameter values. If you fix your macro so that it generates a valid SELECT statement then it works.
%macro data_pull (name=);
proc sql;
select * from sashelp.class where name in &name;
quit;
%mend data_pull;
%data_pull(name=('Alfred','Alice','ben','adam'))
But the real solution is even easier. Just do not include the commas in the value to begin with. The IN operator does not need them. Then you can add the () in the macro code.
%macro data_pull (name=);
proc sql;
select * from sashelp.class where name in (&name);
quit;
%mend data_pull;
%data_pull(name='Alfred' 'Alice' 'ben' 'adam')
Or you can make your macro a little smarter and then the user can either include the () or not when calling the macro.
%macro data_pull (name=);
proc sql;
select * from sashelp.class
where name in (%scan(&name,1,(),q));
quit;
%mend data_pull;
You can use the SYSPBUFF automatic macro variable, which contains the parameter values you supplied to the macro, including the parentheses and commas. The PARMBUFF option allows one to build a macro to deal with a varying number of parameters.
%macro data_pull / parmbuff;
proc sql;
select *
from sashelp.class
where name in &syspbuff.;
quit;
%mend data_pull;
%data_pull('Alfred','Alice','ben','adam')
In this example, the SYSPBUFF variable is ('Alfred','Alice','ben','adam'), which fits nicely for your SQL query.
I am having trouble getting a macro variable to work correctly in PROC SQL and it doesn't make sense to me.
First, if I generate a query like this:
PROC SQL;
SELECT
a.*
,'31MAR2016' As EVAL_DATE format=date09.
FROM
myTable a
;
it works as expected and puts a date field at the end of the table.
Then, if I do this:
%Let testDate = '31MAR2016'd;
%put &testDate;
PROC SQL;
SELECT
a.*
,&testDate As EVAL_DATE format=date09.
FROM
myTable a
;
this again runs properly, with the log window showing the value of:
'31MAR2016'd
But, if I do this:
%Let Eval_Date = %sysfunc(intnx (month,%sysfunc(inputn(201603,yymmn6.)) ,0,E),date09.);
%Let Eval_date_test = %str(%')&Eval_Date.%str(%')d;
%Put Eval_date_test;
PROC SQL;
SELECT
a.*
,&Eval_date_test As EVAL_DATE format=date09.
FROM
myTable a
;
SAS stops running with the error;
"ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant,
a missing value, (, *, +, -, BTRIM, CALCULATED, CASE, EXISTS, INPUT, NOT, PUT, SUBSTRING, TRANSLATE, USER, ^, ~.
ERROR 200-322: The symbol is not recognized and will be ignored."
The log displays the value of &Eval_date_test to be the same '31MAR2016'd as it was in the second example. Note that I created the variable in two steps for clarity, but the same thing happens if you create it in one step.
In case it matters, I am running SAS Enterprise Guide 6.1
Why doesn't this work?
This has to do with how the macro is being dereferenced with the %str() macro. Try the %unquote() macro:
PROC SQL;
SELECT
a.*
, %unquote(&Eval_date_test) As EVAL_DATE format=date09.
FROM
sashelp.cars a
;
quit;
http://support.sas.com/documentation/cdl/en/mcrolref/67912/HTML/default/viewer.htm#p1f5qisx8mv9ygn1dikmgba1lmmu.htm
You are working much too hard and just confusing poor old SAS. Instead of using macro quoting just use the right quote characters to begin with. SAS doesn't care which quote characters you use, but text inside of single quotes is not evaluated for macro triggers and text inside of double quotes is. So '&eval_date'd does not resolve the macro variable reference and "&eval_date"d does.
%let Eval_Date="%sysfunc(intnx(month,%sysfunc(inputn(201603,yymmn6)),0,E),date9)"d;
You're missing a comma after a.*
I am writing a macro that at some point calls some proc SQL code. I want the user to be able to specify arbitrary proc sql options (e.g. inobs=100 could be one of the input arguments to my macro).
I am having a very hard time quoting an argument that has an equality '=' character.
One of the issues is that I should also check if the macro argument is empty or not, and if it is not empty, only then add the specified options to the sql statement.
Below is an example non-working test that does not work and throws the
ERROR: The keyword parameter INOBS was not defined with the macro.
I have read this (http://www2.sas.com/proceedings/sugi28/011-28.pdf) and other SUGI's and tried many possible ways to quote and call the macro.
If somebody could provide a working example of the below function it would be greatly appreciated.
options mprint mlogic;
data have;
length x $8;
input x;
datalines;
one
two
three
;
proc sql inobs=2;
create table sql_output as
select *
from have;
quit;
%macro pass_parameter_with_equal_sign(table=, sqlOptions=);
proc sql
%if "%left(%trim(&sqlOptions.))" ne "" %then %do;
&sqlOptions.
%end;
/* the semicolon to end the proc sql statement */
;
create table macro_output as
select *
from have;
quit;
%mend;
%pass_parameter_with_equal_sign(table=have, sqlOptions=%str(inobs=2))
title "SQL output:";
proc print data=sql_output; run;
title "Macro output:";
proc print data=macro_output; run;
If you remove the %if condition as follows it should work:
%macro pass_parameter_with_equal_sign(table=, sqlOptions=);
proc sql
&sqlOptions.
/* the semicolon to end the proc sql statement */
;
create table macro_output as
select *
from have;
quit;
%mend;
The %if you have used is to check if &sqlOptions is not blank, this shouldn't matter if you use it as it is because its unconditional usage will give either:
proc sql inobs=2; /* in the case of &sqlOptions=inobs=2 */
or if there is no value supplied for &sqlOptions then you should see:
proc sql; /* i.e. no options specified */
So it should work with or without an argument.
Amir's solution is probably correct for your particular use case. But to answer the more general question, we need to look to the seminal paper on macro parameter testing, Chang Chung's Is This Macro Parameter Blank?.
His example C8 is the right one for you here, though some of the others will also work.
%if %sysevalf(%superq(param)=,boolean) %then ... /* C8 */
For example:
%macro test_me(param=);
%if %sysevalf(%superq(param)=,boolean) %then %put Empty;
%else %put Not Empty;;
%mend test_me;
%test_me(param=);
%test_me(param=MyParam);
%test_me(param=param=5);
%SUPERQ is most useful here because it avoids resolving the macro parameter. Instead, it keeps it as a macro parameter value - fully unresolved - and allows you to work with it in that fashion; so you have no risk of that pesky equal sign bothering you.
His C4 (just using SUPERQ without SYSEVALF) also works in this case, although he explains a few situations where it may have difficulty.
Ahh this was actually a tricky little problem you ran into. The issue was actually being caused by the calls to %trim() and %left().
Removing these results in code that works as intended (note I also removed the macro quoting around the parameter):
%macro pass_parameter_with_equal_sign(table=, sqlOptions=);
proc sql
%if "&sqlOptions" ne "" %then %do;
&sqlOptions
%end;
/* the semicolon to end the proc sql statement */
;
create table macro_output as
select *
from &table;
quit;
%mend;
%pass_parameter_with_equal_sign(table=sashelp.class, sqlOptions= inobs=2);
We can re-create the issue you were experiencing like so:
%put %trim(inobs=1);
Because the parameter was resolving to inobs=1, and %trim() doesn't have any named parameters, it was throwing a hissy fit. To correctly pass in a string that contains "inobs=1" we can do so like this:
%let param = inobs=1;
%put %trim(%str(¶m));
Note: Amir's solution of removing the %if statement altogether is also the best way to design code like this. I'm just providing more details as to why you were having this issue.
Additional Explanation 1 - Why %left() and %trim are not needed
The top code snippet provides the same intended functionality as your original code that had the "%left(%trim(&sqlOptions.))". This is because beginning and ending whitespace is dropped from macro variables (including macro parameters) unless it is explicitly retained by using macro quoting. A simple example to show this is:
%let param = lots of spaces ;
%put ***¶m***;
Gives:
***lots of spaces***
You can see that the internal whitespace is kept, but the left and right padding are gone. To keep whitespace, we can simply use the %str() function.
%let param = %str( lots of spaces );
%put ***¶m***;
Gives:
*** lots of spaces ***
Additional Explanation 2 - Working with macros containing whitespace
If you actually did have whitespace on a macro variable that you needed to remove because it was quoted, and you wanted to use %left() and %trim() to do so, then things get a little wacky. Our variable can be created like so:
%let param = %str( inobs = 2 );
You can see we already have quoted the value with %str() in order to create it. This means we can now call one of the functions without having to quote it again:
%put %trim(¶m); * ALREADY QUOTED AT CREATION SO THIS WORKS FINE;
However, if we then try and feed the result into the %left() function we're back to the original issue:
%put %left(%trim(¶m)); * OOPS. DOESNT WORK;
Now I'm guessing here but I believe this is most likely because the %trim() function removes any macro quoting prior to returning a result. Kind of like this:
%put %unquote(%trim(¶m));
This can be circumvented by re-quoting the returned result using %str() again:
%put %left(%str(%trim(¶m)));
... or wrapping the original parameter with a %nrstr():
%let param = %str( inobs = 2 );
%put %left(%trim(%nrstr(¶m)));
... or using %sysfunc() to call a datastep function:
%put %sysfunc(compress(¶m));
Can Somebody please explain me the meaning &, && , % in this SAS code.
I want to convert this code to ECL(HPCC). Thanks
PROC SQL;
create table &RD (compress=binary) as
select a.*,b.Staff_tag2
from &RD a left join (select DISTINCT ucic_id , 1 as Staff_TAG2
from BAL.BAL_&DDMMYYYY1 where prod_code = '102')b
on a.ucic_id=b.ucic_id;
QUIT;
%macro rd();
%do i=1 %to 12;
proc sql;
create table rd.RD_Closed_&&ddmmyyyy&i (compress=binary) as
select V_F_ACCT_ACCT_NUMBER as acct_no,
V_F_ACCT_FIC_CUSTOMER_REF_CODE as ucic_id
from edw.fct_all_accounts_summary
where business_dt eq &&yyyymmdd&i and V_F_ACCT_SOURCE_SYSTEM = 'FINWARERD' AND F_F_ACCT_CLOSED_IND eq 'Y';
quit;
%end;
%mend;
option mprint;
& and && is the beginning of macro variables. They resolve to a value. The value they resolve to depends how they are defined. An example could be:
%let var=test;
in this case &var resolves to test. But there are other ways to initiate macro variables. The %-sign pretty much means that it belongs to the macro languages. There is much to say about SAS macros but i am not sure exactly how much info your after.
I have a global macro variable from another macro which looks like
'01jan2014' when you print it in the log
i.e. there are enforced quotemarks
I want to use this in a proc sql statement but I can't as it doesn't like the variable type.
How do I convert this into a date in the WHERE clause of my proc sql statement?
%let yourdate = 01Feb2015;
%put &yourdate; /* resolve to 01Feb2015 */
proc sql;
select *
from have
where date ge "&yourdate."d;
or
%let yourdate2 = '01Feb2015'd;
proc sql;
select *
from have
where date ge &yourdate2;
I think the first one is better since it won't contain ' in macro variable.
To convert a date string in DDMONYYYY format, simple add a d to the end.
'01jan2014'd
will convert the string to a date.
In your case:
&var.d
will resolve to
'01jan2014'd
which will be interpreted as a date.