Is this possible to pass a string with macro trigger as the macro parameter?
Please see the example code below:
options mprint;
%let string5='%abc%def%';
%macro test(string);
data _null_;
call execute('%test2('||&string.||')');
run;
%mend;
%macro test2(string2);
data test3;
a=%str(%')&string2.%str(%');
run;
%mend;
%test(&string5);
This code ran successfully but it tried to invoke the macro %abc and %def, which resulted in warnings.
If I tried to put it into quoting to mask the string, it gave syntax error, as shown below:
options mprint;
%let string5='%abc%def%';
%macro test(string);
data _null_;
call execute('%test2('||%superQ(string)||')');
run;
%mend;
%macro test2(string2);
data test3;
a=%str(%')&string2.%str(%');
run;
%mend;
%test(&string5);
ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant, a missing value, arrayname, (, +, -, INPUT, NOT, PUT, ^, _NEW_, ~.
Is there a way to fix this without warnings?
Thanks in advance!
Try this:
%let string5='%abc%def%';
%macro test(string);
data _null_;
call execute('%test2('||%nrstr("&string.")||')');
run;
%mend;
%macro test2(string2);
data test3;
a=%nrquote(&string2.);
run;
%mend;
%test(&string5);
It is usually simple enough in the macro to protect against special characters. For example you can use the %superq() function to quote an existing macro variables value.
where name like %unquote(%str(%')%superq(parm1)%str(%'))
Or use the symget() function in a data step to get the value without needing to expand the macro at all.
pattern = quote(symget('parm1'),"'");
But the hard part is making the macro call. You need to protect the characters to get the macro call to run. You can use similar functions in the macro call.
One useful thing to do is to instruct users to pass the parameter value as a quoted string and then the macro code you can remove the quotes when they are not needed.
%macro mymacro(parm1=);
%let parm1=%qsysfunc(dequote(&parm1));
...
%mend;
%mymacro(parm1='fred%')
Or you could ask them to pass the value by name.
%macro mymacro(mvar=);
%local pattern ;
%let pattern=%superq(&mvar);
...
%mend ;
%let my_pattern=%qsysfunc(dequote('fred%'));
%mymacro(mvar=my_pattern)
If this is already working the way you want and you just want to suppress this one warning message, you could consider setting option nomerror; before you run the section of code in question and then setting it back again afterwards.
Just update the final solution I choose. I gave up the way to pass macro parameters between different macros, instead I passed the macro variable name as a string. Sample codes are as below:
options mprint;
%let string5='%abc%def%';
%macro test(string);
data _null_;
call execute('%test2('||&string.||')');
run;
%mend;
%macro test2(string2);
data test3;
a=&&&string2.;
run;
%mend;
%test('string5');
Related
I have a SAS dataset with values
yyyymm
201605
201606
201607
201608
201609
I am trying to find a way to pass these values one at a time to macro such that
do while dataset still has value
%macro passdata(yyyymm);
end
How can I do this in SAS. Can someone please help with a sample/code snippet.
As mentioned by the prior comment, a way to pass parameters is through call execute routine. Note that this must be done in datastep environment. The lines are read from the set you input.
You can input multiple variables. Just add more variables in '||' separators. Note that the variables may have a lot of whitespaces in them. (==Do comparisons with care.)
Here is a small sample code. Tested.
data start_data;
input date_var ;
datalines;
201605
201606
201607
201608
201609
;
run;
%macro Do_stuff(input_var);
%put 'Line generates value ' &input_var;
%mend do_stuff;
data _null_;
set start_data;
call execute('%do_stuff('||date_var||')' );
run;
Try this example and try modifying to meet your needs... From the "source" dataset we can use call symput() to assign a macro token to each observation (differentiated by the SAS automatic dataset variable n so My_token1, My_token2, etc.) Once you have a set of macro variables defined, just loop through them! This program will print all the individual records from source to the SAS log:
data source;
do var=1000 to 1010;
output;
end;
run;
data _null_;
set source;
call symput(compress("My_token"||_n_),var);
run;
%put &my_token1 &my_token4;
%Macro neat;
%do this=1 %to 11;
*Check the log.;
%put &&My_token&this;
%end;
%mend;
%neat;
I need to create sum of 4 variables multiple times each time with new set of variables. For e.g. A1=sum(a1,a2,a3,a4),B1=sum(b1,b2,b3,b4) & so on. So , I am trying to write a macro that will help me do it easily. Following is the code:
%macro SUM2(VAR1,var2,var3,VAR4);
data Subs_60_new;
set Subs_60;
substr(&var1,1,10)=sum(&var1,&var2,&var3,&var4);
run;
%mend sum2;
options mprint mlogic;sum2(ADDITIONAL_INFO_Q1,ADDITIONAL_INFO_Q2,ADDITIONAL_INFO_Q3,ADDITIONAL_INFO_Q4);
I am using SAS EG for the same & when I run the macro I get the following note:
NOTE: Writing TAGSETS.SASREPORT13(EGSR) Body file: EGSR
& obviously when I try to execute the macro it throws an error.
Can some one help me out?
when calling a macro, you need to precede the macro name with a % symbol, eg as follows:
%macro SUM2(VAR1,var2,var3,VAR4);
data Subs_60_new;
set Subs_60;
substr(&var1,1,10)=sum(&var1,&var2,&var3,&var4);
run;
%mend sum2;
options mprint mlogic;
%sum2(ADDITIONAL_INFO_Q1,ADDITIONAL_INFO_Q2,ADDITIONAL_INFO_Q3,ADDITIONAL_INFO_Q4);
The NOTE is harmless. It is ERRORs and WARNINGs in general that you should be concerned with.
I'd point out that this will probably still throw an error, as you are trying to replace characters in a variable (&var1) that appears as though it should contain a numeric field (being part of a sum function). Given your description of what you are trying to achieve, I'd suggest adding the new variable name as another macro parameter - as follows:
%macro SUM2(VAR1,var2,var3,VAR4,varname);
data Subs_60_new;
set Subs_60;
&varname=sum(&var1,&var2,&var3,&var4);
run;
%mend sum2;
options mprint mlogic;
%sum2(ADDITIONAL_INFO_Q1,ADDITIONAL_INFO_Q2
,ADDITIONAL_INFO_Q3,ADDITIONAL_INFO_Q4
,MyNewVariable);
I am debugging a macro I am writing that will treat a string as either a prefix or suffix of a dataset name based on user input. Then, the quoted result will be fed into another process downstream.
So if the user says Type=1 and provides the string 'data_', the output of the resulting macro variable will be 'data_%'.
I've tried a few different iterations of the below code, but can't quite get it....any help would be greatly appreciated. Thanks.
%let Type=1;
%let TableName=data_;
data _null_;
if &Type=1 then
call symput('qTableName',%unquote(%str(%')(cats(&TableName.,"%"))%str(%')));
else if &Type=2 then
call symput('qTableName',%unquote(%str(%')(cats("%",&TableName.))%str(%')));
run;
%put &qTableName;
Looks like you are trying to add single quotes to a macro variable.
%let TableName=data_;
%let qTableName='data_%';
So in a data step you can use CATQ().
data _null_;
call symputx('qTableName',catq('1a',cats(symget('TableName'),'%')));
run;
Or in simple macro code just use %bquote() to allow you to add ' and % without preventing macro variable expansion. But you probably want to remove the macro quoting it will cause.
%let qTableName=%unquote(%bquote('&TableName%'));
Or if you only want to add the % when &TYPE=1 then perhaps you could call the IFC() function. I believe that the %sysfunc() call will remove the macro quoting.
%let Type=1;
%let qTableName=%sysfunc(ifc(&type=1,%bquote('&TableName%'),%bquote('&TableName')));
I have a macro variable, &myvar, but it won't resolve when I try to put it in a data step variable. Why won't it, and what can I do to fix this?
%let myvar=Hello, world;
data _null_;
x='&myvar.';
put x=;
run;
Macro variables in SAS won't resolve when they are in single quotes, '&myvar'. They need to be in double quotes, "&myvar", in order to resolve properly.
If you need to have single quotes and a resolved macro variable, you have a few options, but the simplest is:
%str(%'&myvar.%')
The %' inside of %str will place a single quote character (or apostrophe) in the text string by itself without causing it to be quoted.
data _null_;
x="%str(%'&myvar.%')";
put x=;
run;
or
%let myvar2 = %str(%'&myvar.%');
In SAS 9.4M6 or higher version, you can use %tslit() to achieve the same function.
%let myvar=Hello, world;
data _null_;
x=%tslit(%superq(myvar));
put x=;
run;
%put %tslit(%superq(myvar));
x=Hello, world
'Hello, world'
This is a macro pre-defined in SAS. Here is the documentation about it:
https://documentation.sas.com/?docsetId=lebaseutilref&docsetTarget=n1phgnraoodvpln1bm941n44yq7q.htm&docsetVersion=9.4&locale=en
I have a list of 17 flat files that I'm trying to import into different data sets. All of the files have the same data step, so I'm trying to write a do while loop to import all the files.
I've been trying to adapt some code from here without success:
http://www.sas.com/offices/europe/uk/support/sas-hints-tips/tips-enterprise-csv.html
http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a000543785.htm
I'm getting an error that says the %do statement is not valid in open code. Here is my code:
% let path1 = 'c:\path1'
% let path2 = 'c:\path2'
...
% let pathN = 'c:\pathN'
%let n=1;
%do %while (&n <= 17);
%let pathin = &path&n;
data retention&n;
infile &pathin;
<data step-->
run;
%let n=%eval(&n+1);
%end;
I've tested the data step outside of the do-while loop and it works fine for 1 file at a time using the %let pathin = &path&n code. The code still writes the datafile for the 1st data set; but, I need to be able to loop through all the files and can't figure out how. Sorry if this is a novice question; I'm just learning SAS.
Thanks,
-Alex
Welcome to SAS programming! The error message you got is a clue. "Open code" refers to statements that are executed directly by the SAS system. A %do statment is part of the SAS Macro Language, not "normal" SAS. A %let statement can be executed in open code and is use to create a macro variable (distinct from a compiled macro).
Compiled SAS macros are created by code that appears between the %macro and %mend statements. For example, using your code:
%macro run_me;
%let n=1;
%do %while (&n <= 17);
%let pathin = &path&n;
data retention&n;
infile &pathin;
<data step-->
run;
%let n=%eval(&n+1);
%end;
%mend;
But all that does is define/compile the macro. To execute it, you must issue the statement %run_me;. Note that the name run_me was just a name I made up.
For more info, please consult the SAS Macro Reference, especially the introductory section.
To convert your progma to macro, turn your macro variables declared by LET statement into macro arguments:
%macro readfile(n, pathin);
data retention&n;
infile &pathin;
<data step-->
run;
%mend;
A data step to repetitively call your macro.
Here the data included in CARDS statement, but also can be read from some table via SET statement.
The macro call is performed via call execute routine.
data _null_;
length path $200 stmt $250;
input path;
stmt = catt('%readfile(', putn(_N_, 3. -L), path, ')');
call execute(stmt);
cards;
c:\file1.txt
c:\file2.txt
c:\file3.txt
;
run;