How to resolve a date macro variable in proc step - sas

%macro example
%let begdate = ’01Nov2004’d;
%let enddate = ’30Nov2004’d;
proc sort data=test out=test2;
where date between &begdate and &enddate;
by date;
run;
%mend example;
This code gives me the error: ERROR: Syntax error while parsing WHERE clause.
However, when I simply replace &begdate and &enddate by corresponding values, it works.

I normally run mine like this:
%macro example
%let begdate = 01Nov2004;
%let enddate = 30Nov2004;
proc sort data=test out=test2;
where date between "&begdate"d and "&enddate"d;
by date;
run;
%mend example;
I simply remove any assumptions of a date format and refer to the macro variable in the code as a string. Hope this helps!!

Related

macro for proc sql select into, good for i=1 but not i=2

I was trying to use proc sql select into to generate macro variables, and I would like to do it for all variables in the code dataset, so I embedded it within a macro. The proc sql runs ok for both cd_1 and cd_2 as there are valid print out. However, only cd_1 has the value I wanted, and cd_2 was not resolved. I have pasted the full code below.
data code;
infile datalines delimiter=',';
input MUSCLE $ STIMULANTSFL $ ;
datalines;
baclofen,amphetamine
carisoprodol,dexmethylphenidate
;
run;
*Selecting all the variables names;
proc sql ;
select name into : vars1 - :vars2 from dictionary.columns
where LIBNAME = 'WORK' and MEMNAME = 'CODE';
quit;
*for all names select the codes;
%macro getcode;
%do i=1 %to 2;
PROC SQL ;
select (trim(&&vars&i.)) into : cd_&i. separated by '|' from code where (trim(&&vars&i.)) ne '';
quit;
%end;
%mend;
%getcode;%put &cd_1;%put &cd_2;
Macro variable scope issue - local versus global.
I suspect your first one only works because you tested it. Move the %PUT to inside the macro to have it resolve. Your macro variables do not exist outside your macro unless you explicitly set them to exist.
Add %GLOBAL to create global macro variables.
data code;
infile datalines delimiter=',';
input MUSCLE $ STIMULANTSFL $;
datalines;
baclofen,amphetamine
carisoprodol,dexmethylphenidate
;
run;
*Selecting all the variables names;
proc sql;
select name into : vars1 - from dictionary.columns where LIBNAME='WORK' and
MEMNAME='CODE';
quit;
option mprint;
*for all names select the codes;
%macro getcode;
%do i=1 %to 2;
%global cd_&i;
PROC SQL;
select (trim(&&vars&i.)) into : cd_&i. separated by '|' from code
where (trim(&&vars&i.)) ne '';
quit;
%put cd_&i.;
%end;
%mend;
%getcode;
%put &cd_1.;
%put &cd_2.;

SAS Aggregate to show results for the current year only

I have a table where I compare the results week to week.
I have aggregations of old dates using these functions.
%let date_old=%sysfunc(intnx(year,%sysfunc(Today()),-1,s));
%put &=date_old;
proc format;
value vintf low-&date_old = 'OLD' other=[yymmd7.];
run;
/*agregujemy wyniki do daty vintf jako old*/
proc summary data=tablea_new nway;
class policy_vintage;
format policy_vintage vintf.;
var AKTYWNE WYGASLE;
output out=newtabe sum=;
And I would like to do exactly the same, only to aggregate the dates to show the yearly range, i.e. 2021-01-2022-01. Or the current year 2021-01-2021-12. Is the following sample okay? What's the best way to do this?
%let date_future=%sysfunc(intnx(year,%sysfunc(Today()),+12,s));
%put &=date_future;
proc format;
value vintfutr +&date_future= 'FUTURE' other=[yymmd7.];
run;
%let date_old=%sysfunc(intnx(year,%sysfunc(Today()),-1,s));
%let date_future=%sysfunc(intnx(year,%sysfunc(Today()),+1,s));
proc format;
value vintf
low-&date_old = 'OLD'
&date_future-high = 'FUTURE'
other=[yymmd7.]
;
run;

SAS - Exporting same dataset to multiple excel files

I would like to export the dataset to multiple excel files based on a certain variable:
proc sql;
create table try as
select distinct make from sashelp.cars;
quit;
proc sql;
create table try2 as
select count(make) as aaa from sashelp.cars;
quit;
data _null_;
set try;
by make;
call symputx ('make',compress(make,' .'),'g');
run;
data _null_;
set try2;
call symputx('n',aaa);
run;
%macro a;
%do i=1 %to &n;
%let var= %scan(&make,&i,"#");
proc export data=testing (where=(make="&make."))
outfile="C:\Users\&make..xlsx"
dbms=xlsx replace;
sheet="&make." ;
run;
%end;
%mend ;
%a;
My goal is to get all the 38 excel files with the maker name as the filename.
However, all I am able to get here is the last maker name's file.
Would you please point out where I am missing out here? Many thanks!!
Your first error is that you count the number of cars that have a make, while you should count the distinct makes of cars. Now let me also take the opportunity to explain you the into clause of sql, so you don't need that data step anymore
proc sql;
select count(distinct make)
into :make_count
from sashelp.cars;
quit;
You remove blanks and point from your make names, but you better remove all non-alphabetic characters at once, with compress(make, '', 'ka'), in which the options k stands for keep and a stands for alphabetic.
Your main error is that you think you append all make names in the macro variable make, but you actually overwrite make time and again: first you write "Cadillac" to it, then "Chevrolet" and by the time you ever use it, it became "Volvo".
I could explain you how to correct your datastep, but instead, I will learn you an option of that into statement:
proc sql;
select distinct compress(make, '', 'ka')`
into :make_list separated by ' '
from sashelp.cars;
quit;
The rest is easy.
%macro export_by_make;
%do make_nr=1 %to &make_count;
%let make= %scan(&make_list, &make_nr);
proc export data=sashelp.cars (where=(compress(make, '', 'ka')`="&make."))
outfile="C:\Users\&make..xlsx"
dbms=xlsx replace;
sheet="&make." ;
run;
%end;
%mend;
%export_by_make;
Note that you don't need to specify a separator for the %scan function, as we separated by blanks, but anyway, if you do, as you use the macro version of scan, you don't need the quotes around it.

Proc Sort Using a Macro

I created 40 plus tables (using a marco, which I just learned how to do) that I would like to apply the Proc Sort statement to. I want each table sorted by the same variable 'Account_Description' (each table contains this variable).
The table names are June_53410_v1, June_53420_v1, June_53430_v1, etc. Can I employ a macro, and if so, how can I, to mitigate having to write a proc sort statement for each table?
Thanks!
I found this sample code online but I'm not really sure how it works
%Macro sorter(dsn, var);
proc sort data=&dsn.;
by &var.;
run;
%mend;
%sorter(sample_dataset, age);
Macro that will be used (proc sort write to work):
%Macro sorter(lib,dsn, var);
proc sort data=&lib..&dsn. out=&dsn.;
by &var.;
run;
%mend;
Get dictionary of tables that contains in name some chars (its maby “June_” instead “AIR”) :
data sashelp_tables;
set sashelp.vtable;
where LIBNAME="SASHELP" and MEMNAME contains "AIR"
;
run;
Write code to string , and execute it for all tables:
data _NULL_;
length code $ 200;
set sashelp_tables;
code=cat('%sorter(',LIBNAME,',',MEMNAME,',AIR);');
call execute(code);
run;
I appreciate everyone's input-I think I found an answer though using this code:
%macro st (ds);
proc sort data = &ds;
by Account_Description;
run;
%mend;
%st(June_53410_v1);
%st(June_53420_v1);
You can use this solution, where lib is libname, mask_table is mask to table(June_ in your task) and var is variable to sort tables:
%macro sorter(lib,mask_table, var); %macro d;%mend d;
%let table_list = 0;
proc sql noprint;
select strip(libname) || '.' || strip(memname),count(memname)
into: table_list separated by ' '
from dictionary.tables
where libname = UPCASE("&lib.") and memname LIKE UPCASE("&mask_table.")||"%";
quit;
%do i=1 %to %sysfunc(countw(&table_list,%str( )));
%let name&i = %scan(&table_list, &i, %str( ));
proc sort data=&&name&i.;
by &var.;
run;
%end;
%mend sorter;
%sorter(WORK,June,Account_Description);

Execute proc step only if it doesn't cause log error (inside macro) SAS

I'm trying to test different covariance structures inside macro with Proc Mixed.
%macro cov(type);
proc mixed data=tmp order=data;
class sub trt visit;
model var = trt visit trt*visit / S cl;
repeated visit /subject=sub type=&type.;
FitStatistics=min_var_&type.;
run;
%mend;
Some of the covariance structures I need to fit in model causes errors and I'm trying to find a way to execute this proc mixed statement only, if it doesn't cause error with value of &type.
I have been working with %sysfunc and but haven't been able to resolve this yet.
%IF %SYSFUNC(EXIST(min_var_&type.)) %THEN %DO;
data help_&type.;
set min_var_&type.;
run;
%end;
This produces these datasets correctly, but still log errors exists in log for those macro variables that can not be fitted.
You can redirect the log to a file like that :
filename logfile "\\SERVER\LOG\mylog.log";
proc printto log=logfile new;
run;
And then when your PROC MIXED is finished, you can filter on the log file for the string "ERROR" :
....YOUR PROC MIXED...
/*come back to normal log*/
proc printto;
run;
/*check the log file*/
DATA CHECKLOG;
LENGTH ROWS $200;
LABEL ROWS = 'Messages from LOG';
INFILE "\\SERVER\LOG\mylog.log" TRUNCOVER;
INPUT ROWS &;
LINE = _N_;
IF SUBSTR(ROWS,1,5)='ERROR' /*OR SUBSTR(ROWS,1,7)='WARNING'*/ THEN
OUTPUT;
RUN;
You will have all the ERROR and (or WARNING if needed) in a dataset.
Then you have to check if the table is empty.
If YES, you can continue your script.
You can do it via this method
proc sql;
select * from checklog;
run;
%put n=&sqlobs;
If sqlobs is greater than 0, then you have errors.
You can check the sqlobs via a macro function like this :
%macro checklog;
proc sql;
select * from checklog;
run;
%if (&sqlobs>0) %then ...
%else ...
%mend checklog;