substr function with macro variable name - macros

I am trying to use substr function in SAS macros like this:
%let hg=Name;
data gg_;
set sashelp.class;
gh=%substr(&hg,1,3);
run;
and also I tried
data gg_;
set sashelp.class;
gh=%sysfunc(substr(&hg,1,3));
run;
Here Name is the variable in sashelp.class
But I do not get the first three chars from Name variable into gh.
How do I do it?

You are mixing macro and data step logic.
Since it is a data step, use the SUBSTR() function, not %substr. If the macro variable consists of the text you want to extract then quote it, otherwise leave the macro variable unquoted.
gh=substr(&hg, 1, 3);
Note: edited to reflect comment.

If you are creating a dataset inside a macro function then you want to use the normal sas function so you just need to use substr() instead of %substr().
%let hg=Name;
data gg_;
set sashelp.class;
gh=substr(&hg,1,3);
run;

Related

SAS Macro operations

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

SAS Macro Variable Quoted Concatenation

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')));

SAS: Invalid Date/Time/Datetime constant Error [duplicate]

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

how to name dataset/variable using concatenation

I have a problem with SAS 9.2.
I'm writing a simple macro which creates dataset and name it according to the variables submitted and some other words/letters/signs, for example
%macro example(var1,var2);
data &var1 || '_word_' || &var2;
a=1;
run;
%mend;
Can anyone help?
Pipes are only for strings within SAS, not within SAS macro. So don't use them here.
SAS Macro does not interpret quotes as indicating a string, it will just read them, so leave out the quotes.
If you want to concatenate elements in macro, you just need to write them appended to each other.
To make clear where the macro variable name ends, append a dot.
This should work:
%macro example(var1,var2);
data &var1._word_&var2.;
a=1;
run;
%mend;

Assigning a macro variable value to a data step variable in SAS

I am calling a macro inside a data step and assigning the macro variable to a data step variable as below.
The input for the macro goes from the input dataset which has some 500 records.
%macro test(inp_var);
%global macro_var;
--- using inp_var variable here---
%if --some condition-- %then call symput('macro_var',-- some value--);
%mend;
data output;
set input;
%test(inp_var);
new_data_step_var = symget('macro_var');
run;
But it's showing the error message pointing the variable new_data_step_var - ERROR 180-322: Statement is not valid or it is used out of proper order.
No SAS macro actually executes "inside" a data step. The macro language processor and data step compiler as two different subsystems that share the code input stream. They hand off to one another as they "eat" chunks of SAS code. In the case of the original program, the language processor in SAS sees the "data" statement and hands off to the data step compiler. The embedded %test macro call is detected and the code input stream is handed to the macro processor FIRST! The macro processor expands all of the code and macro logic inside of the %test macro and then the whole stream of code is handed back to the SAS data step compiler to compile.
So %test is going to run to completion BEFORE the data step even compiles.
If you are looking to make your own subroutines in data step try proc fcmp. Otherwise, just implement your conditional logic inside of the data step as was suggested.
Re-write it using datastep if/then, not macro if/then, and don't create a macro variable, simply use a datastep variable.
%MACRO TEST(var) ;
call missing(tempvar) ;
if --some condition-- then tempvar = --some value-- ;
%MEND ;
data output ;
set input ;
%TEST(inp_var) ;
new_var = tempvar ;
drop tempvar ;
run ;
You cannot use a macro variable in the same data step where you set it with call symput.
The result of your call symput statement is only available after the data step.
So at the time the symget statement is being processed, the macro variable does not exist yet.
Also, it seems rather pointless, why don't you use a retain statement to save the value you want?
e.g.:
data output;
set input;
retain new_data_step_var;
if --some condition -- then new_data_step_var = --some value--;
run;
Macros that contain a proc or a data step are not executable inside of a data step. Macros are not functions or subroutines; they are text, just as if you'd typed it out (just saving some time with loops and conditionals). So the contents of your macro need to either be text that could be executed inside a data step:
%macro mymacro(numiters);
*this macro would be easier to do in an array, but it is an example;
%local t;
%do t = 1 to &numiters.;
x&t. = mean(y&t.,z&t.);
%end;
%mend mymacro;
data output;
set input;
%mymacro(5);
run;
In that case, it is easier (and more stylistically correct) to not store a value in a macro variable. Simply contain the result in a data step variable, and if needed pass that variable's name as one of your arguments.
There are also function-style macros, that actually return a value to the data step (or in this case, return text that equates to a value). They can be used on the right side of an equal sign.
%macro xtothey(in,power);
%local t;
&in.
%do t = 1 to &power-1;
*&in.
%end;
;
%mend myfunctionmacro;
data output;
set input;
y = %xtothey(x,4);
run;
That would actually be more easily done in PROC FCMP (which compiles functions and subroutines), but sometimes macros are better for this (or you might not know FCMP well).
Finally, some macros require procs or data steps of their own. In those cases, unless you're using some FCMP elements such as DOSUBL, you will need to store the value somewhere, whether it is in a dataset or a macro. In those cases, you must run the macro prior to the datastep where you want the value - but you only get one (or a finite number of) return values. You don't get one per row unless you go to some extreme lengths, which usually can be done better without using macro variables. I would argue the below is bad form, as you almost always can do it better without using macro variables - but this is how you would do it if you needed to. FCMP with DOSUBL would probably be the superior choice.
%macro findmode(dset,var,outvar);
proc means data=&dset;
var &var.;
output out=_tempset mode(&var.)=&var._mode;
run;
data _null_;
set _tempset;
call symputx("&outvar.",&var._mode);
run;
%mend findmode;
%findmode(sashelp.class,weight,wtmode);
data output;
set input;
mode=&wtmode;
run;