How can I create a character variable in a SAS macro? - macros

I am trying to create two variables, one for year, one for month. The year variable is numeric so the code creates it without problem. However, the month variable is character and the code sees it as blank. How can I fix This? Thanks!
data sourceh.combined&month.&year.;
set sourceh.count;
ratio=count/total;
month=&month.;
year= &year.;
run;

Your code would resolve to :
month = December;
That would be treating the macro variable month as a variable name. To create it as a character variable, you should include it in quotation marks, double quotes so the macro variable resolves.
month = "&month";

Related

How to create a new character variable in SAS from the formats applied to a numeric variable OR How to import SPSS value labels only

I have a series of formatted numeric variables and I would like to convert them all into character variables assigned the corresponding values found in the format labels. Here is an example of the format:
proc format;
value Group
1= 'Experimental 1'
2= 'Experimental 2'
3= 'Treatment as usual';
run;
My variable Group_num has values 1-3 and has this format applied. I want to create a new character variable called Group_char which has the values "Experimental 1", "Experimental 2", and "Treatment as usual".
The (long) way I would do this would be:
data out;
set in;
format Group_char $30.;
if Group_num=1 then Group_char="Experimental 1";
if Group_num=2 then Group_char="Experimental 2";
if Group_num=3 then Group_char="Treatment as usual";
run;
However, I need to do this to 13 different variables and I don't know what their variable values, format names, and format labels are without looking at the data more. Preferably, I would want to use whatever format is already applied to the variable to automatically translate it into a new character variable, without needing to know the format name/labels or original variable values. However, if I need to find out the format name to create a new character variable just by using the format name, that would be better than needing to also know the original variables values and format labels as well.
Alternatively, another way to solve my problem would be if you could tell me if there is a way of importing SPSS datasets using variable value labels only, and leaving the values themselves out of the picture entirely, such that numeric variables with value labels are imported as character variables.
Thank you
First off, it's usually best not to do this - most of the time that you need the character bits, you can get them off of the formats.
But, that said... you need to look at the vvalue function.
data want;
set have;
var_char = vvalue(var_num);
run;
vvalue returns the formatted value of the argument.

Sending automated email from SAS with attachments that changes name

I have files that should be send out every week. These files changes names e.g. "filename_1" next week it will be "filename_2".
But it only takes the filename that I manually wrote which is filename_1. Is there a way to say that it should take the latest file with this name everyweek,instead of me doing it manually every week?
This is my code for the email (I manually wrote the filename):
filename outbox email from="test#test.dk" to="test#test.dk"
type='text/html' subject='test' attach=("F:\filename_1.png" ct='png')
ods html body=outbox rs=none style=Htmlblue;run; ods html close;
The SAS macro facility will help you solve this very problem. If your filenames always have a consistent pattern, you can assign a macro variable to automatically change it for you. For simplicity's sake, let's say your filename always ends with today's date. You can assign a macro variable to hold this value.
%let filename = filename_&sysdate9..png;
This will resolve to filename_14DEC2020.png. You can confirm it with %put &filename.
If your file is sent out weekly and increments in a pattern, some quick math will help us figure out the correct suffix. Let's set a base week to start. We can count the number of weeks from this base week to identify the suffix. In this case, let's say it's today: December 14th, 2020. intck() can count the number of weeks from then until today. Our logic is:
suffix = (Number of weeks from Dec. 14th 2020 to Today) + 1.
In data step language, this is:
suffix = intck('week', '14DEC2020'd, today() ) + 1;
Translated to SAS macro language:
%let suffix = %sysevalf(%sysfunc(intck(week, %sysfunc(inputn(14DEC2020, date9.)), %sysfunc(today()) )) + 1);
%let filename = filename_&suffix..png;
Because we're pulling from data step functions, we need to enclose nearly everything in %sysfunc() to call them. This is one of the functions available that connect the SAS macro facility with the data step language.
Note that we also cannot use date literals directly in the SAS macro facility. We must use inputn() or putn() to convert a human-readable date into a SAS date format.
Simply call this macro variable within your code and it will resolve automatically (except within single quotes).
filename outbox email
from="test#test.dk" to="test#test.dk"
type='text/html'
subject='test'
attach=("F:\&filename" ct='png')
;

How to delete space in character text?

I wrote a code that automatically pulls time-related information from the system. As indicated in the table is fixed t247 Month names to 10 characters in length. But it is a bad image when showing on the report screen.
I print this way:
WRITE : 'Bugün', t_month_names-ltx, ' ayının'.
CONCATENATE gv_words-word '''nci günü' INTO date.
CONCATENATE date ',' INTO date.
CONCATENATE date gv_year INTO date SEPARATED BY space.
TRANSLATE date TO LOWER CASE.
I tried the CONDENSE t_month_names-ltx NO-GAPS. method to delete the spaces, but it was not enough.
After WRITE, I was able to write statically by setting the blank value:
WRITE : 'Bugün', t_month_names-ltx.
WRITE : 14 'ayının'.
CONCATENATE gv_words-word '''nci günü' INTO date.
CONCATENATE date ',' INTO date.
CONCATENATE date gv_year INTO date SEPARATED BY space.
TRANSLATE date TO LOWER CASE.
But this is not a correct use. How do I achieve this dynamically?
You could use a temporary field of type STRING:
DATA l_month TYPE STRING.
l_month = t_month_names-ltx.
WRITE : 'Bugün', l_month.
WRITE : 14 'ayının'.
CONCATENATE gv_words-word '''nci günü' INTO date.
CONCATENATE date ',' INTO date.
CONCATENATE date gv_year INTO date SEPARATED BY space.
TRANSLATE date TO LOWER CASE.
You can not delete trailing spaces from a TYPE C field, because it's of constant length. The unused length is always filled with spaces.
But after you assembled you string, you can use CONDENSE without NO-GAPS to remove any chains of more than one space within the string.
Add CONDENSE date. below the code you wrote and you should get the results you want.
Another option is to abandon CONCATENATE and use string templates (string literals within | symbols) for string assembly instead, which do not have the annoying habit of including trailing spaces of TYPE C fields:
DATA long_char TYPE C LENGTH 128.
long_char = 'long character field'.
WRITE |this is a { long_char } inserted without spaces|.
Output:
this is a long character field inserted without spaces

How to format input for SAS's MONYY format

I currently have a dataset with dates in the format "FY15 FEB". In attempting to format this variable for use with SAS's times and dates, I've done the following:
data temp;
set pre_temp;
yr = substr(fiscal,3,2);
month = substr(fiscal,6,length(fiscal));
mmmyy = month||yr;
input mmmyy MONYY5.;
datalines;
run;
So, I have the strings representing the year and corresponding month. However, running this code gives me the error "The informat $MONYY was not found or could not be loaded." Doing some background on this error tells me that it has something to do with passing the informat a value with the wrong type; what should I alter in order to get the correct output?
*Edit: I see on the SAS support page for formats that "MONYYw. expects a SAS date value as input;" given this, how do I go from strings to a different date format before this one?
When you see a $, it means character value. In this case, you're feeding SAS a character value and giving it a numeric format. SAS inserts the $ for you, but there is no such format in existence.
I'm going to ignore the datalines statement, because I'm not sure why it's there (though I do notice there is no set statement). You might have an easier time just changing your program to:
data temp;
yr = substr(fiscal,3,2);
month = substr(fiscal,6,length(fiscal));
pre_mmmyy = strip(month)||strip(yr);
mmmyy=input(pre_mmmyy,MONYY5.);
run;
you can also remove the "length(fiscal))" from the substring function. The 3rd argument to the substring function is optional, and will go to the end of the string by default.

concatenation in sas using macro

I have two variables with me
%let End_of_month =%sysfunc(intnx(month,'&sysdate'd,-1,e),yymmdd10.);
%stamp =00:00:00
Now, i want to create a new variable
%time_stamp = '2016-06-19 00:00:00'
In order to make this variable , i am using cat function with sysfunc
%timestamp =%sysfunc(cat("'","&End_of_month".,"&stamp.","'"));
The above code is not giving me the desired results. Could somebody tell me how do I solve this using a %sysfunc.
I am not really sure how to use %str and nstr in this statement. Please let me know how can we solve cats, cat and catx in a macro.
Thanks
You initial 2 macro variable are wrong. Then End_of_month should rather be like this
%let End_of_month =%sysfunc(intnx(month,%str(%')&sysdate%str(%'d),-1,e),yymmdd10.);
%put &End_of_month;
OR
%let End_of_month =%sysfunc(intnx(month,%sysfunc(today()),-1,e),yymmdd10.);
%put &End_of_month;
Now coming to the creating a single quotation timestamp with 00:00:00 hr:min:sec afte the date with space as the delimiter, you don't have to use base SAS functions.. simply create the variable like below
%let timestamp=%str(%')&End_of_month 00:00:00%str(%');
%put &timestamp;
Also, %stamp means a macro call which has a definition and not a variable like you've mentioned in your questions.. similarly %timestamp= .. this is syntactically wrong in SAS.. %let timestamp= does macro variable creation and %timestamp would ideally call a timestamp named macro definition..I would suggest reading the SAS Macro Language Reference.
The best way to solve this problem (if it is something you do often) is to create your own format to do so. See this answer:
https://stackoverflow.com/a/24044451/214994
You do not need to use functions to concatenate macro variables. Just expand them where ever you need them in your code. Note also that you do not need to quote string literals in macro code. To the macro processor everything is a string literal.
%let end_of_month=%sysfunc(intnx(month,"&sysdate"d,-1,e),yymmdd10.);
%let time_stamp=&end_of_month 00:00:00;
Adding double quotes is simple.
%let time_stamp="&end_of_month 00:00:00";
Adding single quotes is a pain because the macro references are not resolved inside of single quotes. You could try using %bquote(), but then the value is macro quoted, which can cause trouble. So you might need to also add %unquote().
%let time_stamp=%unquote(%bquote('&end_of_month 00:00:00'));
I have found using the dequote() function is a simple way to introduce single quotes. Start with a string that has double quotes on the outside so that the macro references work and then use %sysfunc(dequote()) to remove the double quotes.
%let time_stamp=%sysfunc(dequote("'&end_of_month 00:00:00'"));