SAS macro output file naming conventions - sas

I have a sas macro which is dependent on two varying variables Age and Year represented by &Age and &Year respectively.
I want to run the macro for each combination of the ages 15-18 and years 2007-2010 and wish to create an output table for each of these combinations (i.e. 16 tables in total).
Here is my problem, I try to give the output table the following name in the macro Matrix_pop_adm&Age_RP&Year which SAS doesn't like.
How can I name my output file correctly ?

As you're concatenating macro variables into a string with other delimiting characters, you need to add dots to make each distinct macro variable resolve (in this case) independently.
Matrix_pop_adm&Age._RP&Year
/* ^ force &AGE to resolve, instead of trying to resolve &Age_RP */

Related

A better way to test if an macro variable is an valid SAS number or not

I am working on a SAS macro to validate if a macro variable is an valid SAS number or not. My solution is based on prxmacth() function:
%macro IsSASnumber(number);
%sysfunc(prxmatch(/^-?(?:\d+|\d*\.\d+)(?:e-?\d+)?|\.[a-z]?$/i,&number));
%mend;
There are several examples:
%put %IsSASnumber(123);
1
%put %IsSASnumber(1.23);
1
%put %IsSASnumber(-.12e-3);
1
%put %IsSASnumber(.N);
1
%put %IsSASnumber(.tryme);
0
My question is:
Is this regular expression covers all condition?
Is there a shorter or faster way to achieve this?
Ps: Assume the input is not empty.
If the goal is to support using the INPUT() function without generating error messages when the strings do not represent numbers then just use the ? or ?? modifiers to suppress the errors.
Since the INPUT() function does not care if the width used on the informat specification is larger then the length of the string being read just use the maximum width the informat supports. So just use:
number = input(variable,??32.);
You might also want to test the length of VARIABLE, the numeric informat can only handle strings up to 32 bytes long. You might want to remove any leading spaces.
if length(left(variable)) <= 32 then number=input(left(variable),??32.);
If you want strings like "N" or "X" to be treated as meaning the special missing values .N and .X then make sure to tell SAS that in advance by using the global MISSING statement. To support all 27 special missing values use a missing statement like this:
missing abcdefghijklmnopqrstuvwxyz_ ;
If you want to treat '.N' as meaning .N instead of . then you will need to test for that string. To test all of them you could use something like:
if missing(number) and length(variable)=2 and char(variable,1)='.'
then number=input(char(variable,2),??32.)
;
Note: make sure to use the name of an INFORMAT when using the INPUT() function. BEST is the name of a FORMAT (the name makes no sense as a name for an informat since there is only one way to represent a number as a number). If you use BEST as an INFORMAT SAS will just treat it as an alias for the normal numeric informat.
The %datatyp macro can determine all of these, but it fails at .N. You can simplify your use case this way:
%macro IsSASnumber(number);
%sysevalf(%datatyp(&number) = NUMERIC OR %sysfunc(prxmatch(/^\.[A-Z_]$|^\.$/i, &number)));
%mend;
This will match your numeric cases, and then you can match the . cases.

Rename SAS variables containing special characters

After I imported a huge Excel file containing thousands of data into the SAS, I found some variables showing names with special characters. For example, I have variable names like "pre.tal" and "miss.auto.t0". SAS doesn't allow me to proceed with the statistical analysis due to the special characters in these variable names. I tried the following codes but failed to work. Any ideas? Thanks
options validvarname=any;
data one;
set one;
rename pre.tal_month_t0 = 'prenatal_month_t0'n;
run;
It is the name with special characters that needs quotes and an "n":
rename 'pre.tal_month_t0'n = prenatal_month_t0;
And by the way, if you want to see your original names in listings, you can assign a label to variables
data one;
set one;
rename 'pre.tal_month_t0'n = prenatal_month_t0;`
label prenatal_month_t0 = 'pre.tal_month_t0';
proc print data=one labels;
run;
If you are pressed for time, change the option to validvarname=v7. SAS will automatically make variable names with letters and numbers while replacing special characters and whitespace with underscores. Then you don't have to worry about using name literals ('...'n).
Using options validvarnames=v7; which will allows to use

How to recall a numeric macro variable with a string prefix in SAS

I obtain an error in SAS while creating a new field in a dataset recalling a numeric macro variable. Here there's an example.
data input;
input cutoff_1 cutoff_2;
datalines;
30 50
;
data db;
input outstanding;
datalines;
1000.34
2000.45
3000.90
5000.98
8000.02
;
data _null_;
set input;
call symput("perc1",cutoff_1);
call symput("perc2",cutoff_2);
run;
proc univariate data=db noprint;
var outstanding;
output out=test
pctlpts = &perc1. &perc2.
pctlpre = P_;
run;
data test2;
set test;
p_&perc1._round=round(P_&perc1.,1);
p_&perc2._round=round(P_&perc2.,1);
run;
From the log it seems that the macros &perc. are solved, but that it's not possible to use those results (30, 50) to name a new variable in the dataset test2. What am I missing?
When you ask normal SAS code to use a numeric value in a place where a character value is required (both arguments to CALL SYMPUT() require character values) then SAS will convert the number into a string using the BEST12. If the value does not require all 12 characters it will be right aligned. So you created macro variables with leading spaces. The leading spaces make no difference for generating pctlpts= option values as extra spaces will not matter there. But having the leading spaces mean you are generating code like:
p_ 30_round=round(P_ 30,1);
You should use the modern (probably over 20 years old) CALL SYMPUTX() function instead. That function will remove leading/trailing spaces from the second argument when creating the macro variable. It also accepts a numeric value as the second argument converting the number into a character string using a format more like BEST32 instead of BEST12.
call symputx("perc1",cutoff_1);
call symputx("perc2",cutoff_2);
The only cases where you should ever use the ancient CALL SYMPUT() function is when you actually need to create macro variables that contain leading and/or trailing spaces.
Other solutions are to remove the spaces in the function call
call symput("perc1",strip(put(cutoff_1,best32.)));
or after generating the macro variables.
%let perc1=&perc1;
One possible solution is to use call symputx and not call symput. With call symputx the variables created are globally defined.

symputx won't let me store different macro variables with the same macro function

I'm trying to write a macro function that gets attributes from a data set, and then stores them as a macro variable. I want to write this macro function in such a way that it can be used for multiple data sets, and multiple macro variables.
What's wrong with this:
%macro ExtractACell(dataset, storage_var, rownum=1, var_name=Make);
data _null_;
set &dataset. (obs=&rownum. firstobs=&rownum. keep = &var_name.);
call symputx(&storage_var., &var_name., "G");
stop;
run;
%mend ExtractACell;
Whenever I try to run that I get notes like this:
NOTE: The quoted string currently being processed has become more than 262 bytes long. You might have unbalanced quotation marks.
NOTE: The quoted string currently being processed has become more than 262 bytes long. You might have unbalanced quotation marks.
27 %let SASWORKLOCATION="%sysfunc(getoption(work))/";
Does symputx have rules against passing in macro variables that represent names of macro variables?
Make sure you are generating valid SAS code when your macro variables are expanded. In particular this statement:
call symputx(&storage_var., &var_name., "G");
Would require you to call the macro with quotes around the name of the macro variable you want it to create. Like this:
%ExtractACell(dataset=sashelp.cars, storage_var="mymvar", rownum=1, var_name=Make);
It might be simpler to code the macro using this statement.
call symputx("&storage_var", &var_name., "G");
Then you could call without the quotes around the macro variable name:
%ExtractACell(dataset=sashelp.cars, storage_var=mymvar, rownum=1, var_name=Make);
PS Your whole process is probably messed up if you need that macro.

Extract left part of the string in SAS?

Is there a function SAS proc SQL which i can use to extract left part of the string.it is something similar to LEFT function sql server. in SQL I have left(11111111, 4) * 9 = 9999, I would like to something similar in SAS proc SQL. Any help will be appreciated.
Had an impression you want to repeat the substring instead of multiply, so I'm adding REPEAT function just for the curiosity.
proc sql;
select
INPUT(SUBSTR('11111111', 1, 4), 4.) * 9 /* if source is char */
, INPUT(SUBSTR(PUT(11111111, 16. -L), 1, 4), 4.) * 9 /* if source is number */
, REPEAT(SUBSTR(PUT(11111111, 16. -L), 1, 4), 9) /* repeat instead of multiply */
FROM SASHELP.CLASS (obs=1)
;
quit;
substr("some text",1,4) will give you "some". This function works the same way in a lot of SQL implementations.
Also, note that this is a string function, but in your example you're applying it to a number. SAS will let you do this, but in general it's wise to control you conversion between strings and numbers with put() and input() functions to keep your log clean and be sure that you're only converting where you actually intend to.
You might be looking for SUBSTRN function..
SUBSTRN(string, position <, length>)
Arguments
string specifies a character or numeric constant, variable,
or expression.
If string is numeric, then it is converted to a character value that
uses the BEST32. format. Leading and trailing blanks are removed, and
no message is sent to the SAS log.
position is an integer that specifies the position of the first
character in the substring.
length is an integer that specifies the length of the substring. If
you do not specify length, the SUBSTRN function returns the substring
that extends from the position that you specify to the end of the
string.
As others have pointed out, substr() is the function you are looking for, although I feel that a more useful answer would also 'teach you how to fish'.
A great way to find out about SAS functions is to google sas functions by category which at the time of writing this post will direct you here:
SAS Functions and CALL Routines by Category
It's worth scanning through this list at least once just to get an idea of all of the functions available.
If you're after a specific version, you may want to include the SAS version number in your search. Note that the link above is for 9.2.
If you have scanned through all the functions, and still can't find what you are looking for, then your next option may be to write your own SAS function using proc fcmp. If you ever need assistance with doing this than I suggest posting a new question.