I have the following variables:
%let curr_score_date = '31DEC2013'D;
%let target_date = %sysfunc(intnx(month,&curr_score_date,12,e));
%let prod_start_date = %sysfunc(intnx(month,&curr_score_date,-11,b));
%let prod_end_date = %sysfunc(intnx(month,&curr_score_date,0,e));
If evaluating based on this documentation, I evaluate each statement on its own to:
target_date = '31Dec2014'
prod_start_date = '01Jan2013'
prod_end_date = '31Dec2013'
However, I am wondering if each step just returns a value, or actually updates &curr_score_date. If it was updated at each calculation, this would certainly affect the results.
In SAS, functions return values (and cannot change their arguments), while call routines can change their arguments.
As such, in the above, &curr_score_date cannot be changed by use of %sysfunc.
Related
I am facing an issue with the % let statement I have not found yet the correct answer, and I am not sure if something can be done.
I am facing the following issue, hope someone can help.
I have this macro statement.
%let num = 5;
%let c&num.act = %str(re&num);
I want that the %let c&num.act gets the value c5.act, but it is not working this way.
So the last let statement is resolve this way:
c5.act = re5
Can you give me some help?
It sounds like the question is NOT about %LET statements. Instead you seem to be confused about how to reference the macro variable that you created with the %LET statement.
So these two statements
%let num=5;
%let c&num.act = re#
create two macro variables. NUM and C5ACT.
To see the values you can use code like this:
%put #
%put &&c&num.act ;
When you have two & triggers next to each other the macro processor will replace them with a single & and remind itself to re-process the resulting string for further macro expansion.
On the first pass &&c&num.act will be transformed into &c5act which will then be re-evaluated and result in value re5 that was assigned by the second %LET statement.
In my SAS code I would like to refer to an existing folder based on the date value (LADE_DATUM) that I declare with a prompt. From this date I define LADE_JAHR and LADE_MONAT:
%let LADE_JAHR = %sysfunc(year("&LADE_DATUM"D));
%let LADE_MONAT = %sysfunc(month("&LADE_DATUM"D));
Based on these two variables I would like to refer to some existing folders (importpfad) that look like:
2020-09, 2020-10, 2020-11, 2020-12, etc.
This is the code:
data _null_;
if &lade_monat < 10 then a = '0'; else a = '';
call symput('a',a);
%let importpfad = /folderx/Input_Files/**&lade_jahr/&lade_jahr.-&a.&lade_monat**/;
The problem is, if a = '' then the folder it refers to looks like "2020- 10" instead of "2020-10".
So there is a space between that I don't want to have.
If a is between 1 and 9, everything is OK.
Just tell %SYSFUNC() you want the month number generated with the Z format instead of the default best format.
%let LADE_MONAT = %sysfunc(month("&LADE_DATUM"D),Z2.);
%let importpfad = /folderx/Input_Files/&lade_jahr/&lade_jahr.-&lade_monat/;
Maintaining somebody else's SAS project, I found some code snippet which creates a table input-stats within a data step. The variable &all. contains a list of tables to examine. The data step is rather long which I shortened here with /* more code */:
%let all = "work.table1*mywork.table2";
data input-stats;
i = 1;
do while (scan(&all., i, '*') ne '');
name = scan(&all., i, '*');
/* more code */
output;
i = i + 1;
end;
run;
I want to expand the table input-stat with yet another column giving me the number of lines of each table. I found the following macro within the project to do exactly this:
%macro count_rows(ds);
%let DSID=%sysfunc(OPEN(&DS.,IN));
%let NOBS=%sysfunc(ATTRN(&DSID.,NOBS));
%let RC=%sysfunc(CLOSE(&DSID.));
&nobs
%mend;
I would like to now integrate this call within the above mentioned data step, but obviously, I cannot just simply add a rows=%count_rows(name) (e.g. instead of /* more code */) as I would in other programming languages.
How would you solve this issue with minimal code modifications? Is there a way without making a huge %while loop?
The functionality of the macro code can be replicated in DATA Step scope by invoking the same functions. No need for macro and intermingling scopes that can be confusing when using RESOLVE or CALL EXECUTE.
...
name = scan(&all., i, '*');
/* more code */
* add row counting code here;
_dsid = open (name,'IN');
nobs = attrn(_dsid,'NOBS');
_dsid = close (_dsid);
drop _:;
output;
...
I am facing this issue with sas data step. My requirement is to get a list of variables such as
total_jun2018 = sum(jun2018, dep_jun2018);
total_jul2018 = sum(jul2018, dep_jul2018);
Data final4;
set final3;
by hh_no;
do i=0 to &tot_bal_mnth.;
bal_mnth = put(intnx('month',"&min_Completed_dt."d, i-1), monyy7.);
call symputx('bal_mnth', bal_mnth);
&bal_mnth._total=sum(&bal_mnth., Dep_&bal_mnth.);
output;
end;
But I am facing error that macro variable bal_mnth not resolved. Also once it did ran successfully but I want that output must be printed sequentially but it only prints output for last loop when i=6 then it prints only Total_DEC2018=sum(DEC2018, DEP_DEC2018);
Any help will be appreciated!
Thanks,
Ajay
This is a common issue when learning SAS Macro. The problem is that the macro processor needs to resolve &bal_mnth to a value when the data step is first submitted for execution, but the CALL SYMPUT doesn't execute until the data step is actually executed, so at the time you submit the code, there is no value available for &bal_mnth.
In this case you don't need bal_mnth to be created as a variable in the data set, so you could replace the line that starts bal_mnth = put(intck(...)) with a %let bal_mnth = ... statement. The %let executes while the data step is being submitted, so that way its value will be available when you need it.
My proposed %let statement will need to wrap the functions in at least one SYSFUNC call, which is left as an exercise for the reader :-)
It looks like you want to generate a series of assignment statements like:
total_jun2018 = sum(jun2018, dep_jun2018);
total_jul2018 = sum(jul2018, dep_jul2018);
...
total_jan2019 = sum(jan2019, dep_jan2019);
What is known as wallpaper code.
If your variables names were easier, such as dep1 to dep18 then it would be easy to use arrays to process the data. With your current naming convention the problem with generating the array statements is not much different than the problem of generating a series of assignment statements.
You can create a macro so that you could use a %DO loop to generate your wallpaper code.
%local i bal_mnth;
%do i=0 %to &tot_bal_mnth.;
%let bal_mnth = %sysfunc(intnx(month,"&min_Completed_dt."d, &i-1), monyy7.);
total_&bal_mnth = sum(&bal_mnth , Dep_&bal_mnth );
%end;
Or you could just generate the code to a file with a data step.
%let tot_bal_mnth = 7;
%let min_Completed_dt=01JUN2018;
filename code temp;
data _null_;
file code;
length bal_mnth $7 ;
do i=0 to &tot_bal_mnth.;
bal_mnth = put(intnx('month',"&min_Completed_dt."d, i-1), monyy7.);
put 'total_' bal_mnth $7. ' = sum(' bal_mnth $7. ', Dep_' bal_mnth $7. ');';
end;
run;
So the generated file of code looks like this:
total_MAY2018 = sum(MAY2018, Dep_MAY2018);
total_JUN2018 = sum(JUN2018, Dep_JUN2018);
total_JUL2018 = sum(JUL2018, Dep_JUL2018);
total_AUG2018 = sum(AUG2018, Dep_AUG2018);
total_SEP2018 = sum(SEP2018, Dep_SEP2018);
total_OCT2018 = sum(OCT2018, Dep_OCT2018);
total_NOV2018 = sum(NOV2018, Dep_NOV2018);
total_DEC2018 = sum(DEC2018, Dep_DEC2018);
You can then use %include to run it in your data step.
data final4;
set final3;
by hh_no;
%include code / source2 ;
run;
I would like to offer another point of view: the difficulty you are having here results from the use of a wide data shape, with lots of columns.
Rather than working with your data in this shape, you could first transpose from wide to long, so that instead of having lots of total_xxx columns you just have 3: total, total_dep and date, with one row per month. Once it's in this format, it will be much easier to work with, potentially allowing you to avoid resorting to macros and wallpaper code.
Suggested reading:
Transpose wide to long with dynamic variables
I'm new to SAS. I encurred into a problem when trying to declare a macro variable with the result of some operation as value.
data _null_;
%let var1 = 12345;
%let var2 = substr(&var1., 4,5);
run;
I get that var2 has value substr(&var1., 4,5) (a string) instead of 45 as I would like. How to make the variable declaration evaluate the function?
Sorry it the question is trivial. I looked in the documentation for a bit but couldn't find an answer.
There is a macro equivalent called %substr() which can be used as follows:
%let var1 = 12345;
%let var2 = %substr(&var1., 4,2);
%put var2 = &var2;
Note that the data and run statements are not required for macro language processing and the 3rd argument to %substr() (and substr()) specifies the length you want, not the position of the last character, which is why I used 2 instead of 5.
Edit: Also, if there is no macro equivalent then you could use %sysfunc() to make use of the data step function in macro code. See the documention for full details as there are some quirks, such as not using quotes and a few exceptions to the list of data step functions that can be used.