Writing a macro in SAS to create a table - sas

Very new to SAS Programming. Want to start with something simple - writing a macro that run an append query. This is all I have managed to figure out. Where am I going wrong?
%MACRO APPENDTEST;
PROC SQL;
CREATE TABLE WORK.APPENDTEST AS
SELECT *
FROM WORK.MONTHLY_SALES_SUMMARY
QUIT;
%MEND APPENDTEST;

You've created a macro but have executed it. This functionality, similar to a function in other languages, allows a macro to compile and execute and different times.
Adding in the following line will call the macro.
%appendtest;

Related

Checking to see if a dataset exists

I've just finished the main macro for a project that I'm on. It generates a line to enter into another table. So, my next step is to write another macro that calls this one. One of the arguments for this next macro is the name of the dataset in which to insert this new observation, which leads to my question...
I'd like for my next macro to check and see if the named dataset exists. If so, it will insert the new calculated line into the dataset. If it dose not yet exist, I'd like to save the new line as a dataset with this name.
To get a little bit more concrete, let's suppose I have the macro
%calculate_for(ARG1, ARG2, ARG3) that creates a single-observation dataset NEXT_LINE. I want to write a macro that does something like:
%macro do_for(ARG1, ARG2, ARG3, DATASET_NAME);
%calculate_for(&ARG1, &ARG2, &ARG3)
{if DATASET_NAME exists then do:}
data &DATASET_NAME;
set &DATASET_NAME
NEXT_LINE;
run;
{if DATASET_NAME doesn't exist yet then do:}
data &DATASET_NAME;
set NEXT_LINE;
run;
%mend;
How might I go about doing this in SAS?
The macro function %SYSFUNC can be used to invoke almost any DATA step function.
For example
%macro …;
data &out;
set
%if %sysfunc (EXIST(&OUT,DATA)) %then %do;
&OUT
%end;
NEXT_LINE;
;
run;
%mend;
Likewise, the %SYSCALL routine can be used to invoke almost any CALL routine.
As #Reeza comments, for the specific coding case in your question, Proc APPEND could be the better choice. The pattern shown in your sample code would cause an entire rewrite of the base table.
Other coding patterns that do not rewrite the entire data set include
DATA Step : MODIFY statement with subsequent OUTPUT, REPLACE or REMOVE statements
Proc SQL : INSERT INTO … SELECT … FROM
If you are doing a lot of development, perhaps don't recreate the wheel at every step. Look around for SAS macro libraries that have common utility features, one example Roland's SAS® Macros

SAS - Dynamically creating macro variable via concatenation of text to a current macro variable

I'm looking to create a macro variable. The macro variable name needs to be made by concatenating text to an already existing variable after it has resolved. Specifically, I want to do this in a PROC SQL block using INTO:. Here's a snippet to explain what I want to do.
%macro MyMacro(process);
PROC SQL;
SELECT
COUNT(*) INTO: &process._new_text
FROM
DataSetHere
;QUIT;
%mend MyMacro;
If I call on this macro and I pass the word "cat" into process, I want to have now declared/initialized a variable with the name cat_new_text, and it should return the COUNT(*) selected in that query whenever &cat_new_text is referenced.
I've done a little reading around, looked into using multiple ampersands, trying to resolved &process within quotes first - nothing has really solved my exact problem. Does anyone know of a clear cut way to accomplish this?
Thanks in advance!
Your code seems fine and it seems like it would do exactly what you describe.
However if your trying to "access" that new macro variable outside the macro, e.g.,
%MyMacro(cat);
%put &cat._new_text.;
then indeed it will not work because the variable was created locally in your macro and does not exist outside the scope of that macro.
To fix that, you simply need to add a %global statement in your macro definition:
%macro MyMacro(process);
%global &process._new_text;
PROC SQL;
SELECT COUNT(*)
INTO: &process._new_text
FROM DataSetHere
;
QUIT;
%mend MyMacro;

declare variabe in PROC SQL (SAS)

I am trying to use a variable on PROC SQL but i cannot find a proper way through the internet. I just want to apply the following code of T-SQL on PROC SQL:
declare #example as int;
set #example=2;
select * from {table} where {column}=#example;
go
How can i apply this code on PROC SQL?
The translation to SAS SQL is to use a macro variable, the code looks pretty similar, need to wrap it in a PROC SQL block though.
%let example=2;
proc sql;
select *
from table
where variable=&example;
quit;
EDIT: my original reference to the macro variable was incorrect, use an ampersand in SAS not # symbol.

Dynamically create define in a PROC REPORT

I have a dataset(liste_institution) that contain all the name of the variable that I want to "define" in my proc report statement. Here is my code that work when I call my macro not dynamically(%create_institution(815);). If I use the data statement with the call execute(in comment in my code) it not working. The reason seem to be that when I use the call execute the code is not interpreted in a PROC REPORT that is why it give me error.
proc report data = ventes_all_inst4
missing split = "*" nowd
style(header)=[font_weight=bold background = #339966 foreground = white]
style(column)=[cellwidth=15cm];
%macro create_institution(institution);
define TOTAL_&institution. / display "TOTAL*($)" style(column)=[cellwidth=4cm];
%mend;
/* Give error when I use this data step */
/*data _null_;
set liste_institution;
call execute('%create_institution(' || INS || ');');
run;*/
%create_institution(815);
run;
Is there an easy way to create dynamically define statement in a PROC REPORT from a dataset that contain the column name.
Basically, you have a misunderstanding of how macros work and timing. You need to compile the macro list previous to the proc report, but you can't use call execute because that actually executes code. You need to create a macro variable.
Easiest way to do it is like so:
proc sql;
select cats('%create_institution(',ins,')')
into :inslist separated by ' '
from liste_institution
;
quit;
which makes &inslist which is now the list of institutions (with the macro call).
You also may be able to use across variables to allow this to be easier; what you'd have is one row per ins, with a single variable with that value (which defines the column name) and another single variable with the value that goes in the data table portion. Then SAS will automatically create columns for each across value. Across variables are one of the things that makes proc report extremely powerful.

SAS: How to assign the output value of a function-like macro?

I am very new using SAS and Im having hard time trying to assign the output value of a function-like macro to a macro variable. After testing, I have check that the value is computed correctly, but once I tried to assign it the program crashes. here you can find the code
%MACRO TP_BULLET(ZCURVE,TAU,YF=1);
/* KEEP ONLY THE ZERO CURVE UNTIL MATURITY*/
DATA _TEMP;
SET &ZCURVE;
IF MATURITY > &TAU THEN DELETE;
RUN;
PROC SQL NOPRINT;
SELECT DISTINCT 1- DF
INTO :NUME
FROM _TEMP
GROUP BY MATURITY
HAVING MATURITY = MAX(MATURITY);
QUIT;
PROC SQL NOPRINT;
SELECT SUM(DF)
INTO :DENO
FROM _TEMP;
QUIT;
PROC DELETE DATA=_TEMP;RUN;
%LET TP = %SYSEVALF(&YF*&NUME / &DENO);
&TP
%MEND TP_BULLET;
%MACRO TESTER2;
%LET K = %TP_BULLET(ZCURVE,TAU,YF=1);
%PUT .......&K;
%MEND TESTER2;
%TESTER2;
The error I am getting is the following
WARNING: Apparent symbolic reference DENO not resolved.
WARNING: Apparent symbolic reference NUME not resolved.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
1*&NUME / &DENO
So I suppose that the DATA Step is failing to create the sas table _TEMP, but I have no idea how to solve it. Thanks in advance for any help or sugestion
This is NOT a 'function like' macro - you are mixing SAS Macro language and Base SAS. Remember that the SAS Macro language is a code generator - and you are generating code, which is currently something like:
%let K=data _temp; set ZCURVE; ....
note how the above is not what you wanted to assign to the macro variable K.
To help with this, try running your macro with options mprint - this will show you the code being generated by your macro.
If you want your macro to act like a function, then (at a minimum) you should find NO code being generated via the mprint option..
All philosophical issues aside, you could add a parameter to your macro that specifies the new macrovariable (mv) that you want to create. So instead of
%Let k = %TP_BULLET(ZCURVE,TAU,YF=1);
you could call
%TP_BULLET(ZCURVE,TAU,mvOutput=k,YF=1);;
Your macro would need to be modified slightly with
%MACRO TP_BULLET(ZCURVE,TAU,mvOutput,YF=1);
%GLOBAL &mvOutput;
........ Same code as above .........
%Let &mvOutput = &TP; *Instead of final line with '&TP';
%MEND;
It is not a very SAS-y way to accomplish it, but it can help keep things more modular and comprehensible if you're working with more programming backgrounds, rather than SAS.