Conditional Formatting in SAS with Macros - sas

Hi I'm trying to apply conditional formatting to a table in SAS. The conditional formatting will be highlighting data in columns (variables). If the field is "Y" then highlight green, else if the field is "N" then red.
The input table looks like this:
My goal is to have it looks something like this
I currently have this code in my macro:
%LET NVARS= 6;
%LET to_date= '01SEP2022'd;
%macro cf();
PROC REPORT DATA=work.process /*the data set input */ OUT=work.test1;
COLUMN SKU HIGH PRI COST_CTR
%DO i = 1 %TO &NVARS.;
SUPPORT&i.
%END;
%DO i =1 %TO &NVARS.;
DEFINE SUPPORT&i. / DISPLAY
STYLE (column)={just=center};
%END;
%DO i =1 %TO &NVARS.;
COMPUTE SUPPORT&i.;
IF SUPPORT&i. ='Y' THEN CALL DEFINE (_col_,'style','style={background=vilg}');
IF SUPPORT&i. ='N' THEN CALL DEFINE (_col_,'style','style={background=viypk}');
ENDCOMP;
%END;
RENAME
%DO i =1 %TO &NVARS.;
SUPPORT&i. = %SYSFUNC(INTNX(month,&to_date.,&I-1),monyy7)
%END;
RUN;
%MEND;
%cf();
For some reason it's erroring out and not doing the conditional formatting. I then want to export the output in excel. Any help is greatly appreciates from SAS gurus.

Personally, I would use PROC PRINT to do this instead of PROC REPORT.
Create a format to format Y as green, N as red
Use PROC PRINT to display information
Create labels dynamically instead of rename to display the months name dynamically.
Use ODS EXCEL to pipe the formatted output including colours directly to Excel (tested and it works).
proc format;
value $ support_fmt
'Y' = 'vilg'
'N' = 'viypk';
run;
ods excel file = '/home/fkhurshed/Demo1/demo.xlsx';
%macro cf;
%LET NVARS= 6;
%LET to_date= '01SEP2022'd;
proc print data=have label noobs;
var sku high_pri cost_ctr ;
var support1-support6 / style={background=$support_fmt.};
%do i=1 %to &nvars;
label support&i. = %sysfunc(intnx(month, &to_date, %eval(&i-1)), monyy7.);;
%end;
run;
%mend;
%cf;
ods excel close;

Related

SAS Grid Enabling

I have to pull a lot of data and I am trying to grid enable it to run faster. Unfortunately, I am not a SAS coder so I am trying to modify existing code. I keep getting a 'no matching %DO statement for the %END' error in the waitfor all section of the log. I am not even sure this would work otherwise.
Does someone have grid experience to help me out?
%let _sdtm=%sysfunc(datetime());
%macro splitmonths(begmonth=,endmonth=);
%let rc=%sysfunc(grdsvc_enable(_all_,server=SASApp));
options autosignon;
%do imth=&begmonth %to &endmonth;
signon t&imth;
%syslput imth=&imth/remote=t&imth;
rsubmit t&imth wait=no;
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_VW_HOUPOSSW_FACT_&imth AS
SELECT t1.outletfamily,
t1.ppmonth,
t1.itemnumber,
/* Dollars */
(SUM(t1.totalvalue)) FORMAT=DOLLAR20. AS Dollars
FROM HOUPWP7.vw_houpossw_fact t1
WHERE t1.ppmonth = &imth;
GROUP BY t1.outletfamily,
t1.ppmonth,
t1.itemnumber;
QUIT;
endrsubmit;
%end
waitfor _all_
%do imth=&begmonth %to &endmonth;
t&imth
%end;
;
signoff _all_;
data newdata;
set
%do imth=&begmonth %to &endmonth;
newdata&imth
%end;
;
run;
proc datasets lib=work;
%do imth=&begmonth %to &endmonth;
delete newdata&imth;
%end
quit;
%mend splitmonths
%splitmonths (begmonth=541, endmonth=588)
%let _edtm=%sysfunc(datetime());
%let _runtm=%sysfunc(putn(&_edtm - &_sdtm, 12.4));
%put It took &_runtm second to run the program;enter code here
Trying adding semi-colon to end the %end macro statement just before the start of the waitfor statement.
%end;
waitfor _all_

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;

SAS Proc Report Title Error

I have an issue where by the do loop creates my reports however the title page where the macro is listed doesn't reflect the correct naming convention each time.
It works for each of the bookmarks in PDF as well as the proc report itself. However the titles don't reflect correctly.
%macro PDF_T2(year=, age= );
proc sql noprint;
select distinct region, bh_type
into :region1 - :region14, :bh_type1 - :bh_type14
from table2_IP
;
quit;
/*%put &region1 &region2;*/
/*%put &bh_type1 &bh_type2;*/
ods escapechar '^';
ods pdf file="C:\PDFS\Table2.pdf" pdftoc=2 style=Custom;
options orientation=landscape missing=' '
topmargin=.25in
bottommargin=.25in
leftmargin=.25in rightmargin=.25in ;
ods proclabel " Inpatient Analysis By Plan ";
%do i=1 %to 4;
TITLE "^{style [JUST= C ]Table 2. Inpatient Utilization By Plan,}";
TITLE2 "^{style [JUST= C ]&&region&i. }" ;
Title3 "^{style [JUST= C ]Adult (21 to 64)}";
Title4 "^{style [JUST= C ]&&bh_type&i. Analysis}" ;
PROC REPORT DATA = Table2_IP contents="&&bh_type&i. Table: Inpatient`enter code here`
I would try making sure that you are using %local macro variables. If you have global macro variables floating around that could cause some surprising results.
I would also turn on MPRINT and look at the log to see what code is being generated. It will show the TITLE statements that the macro is generating.
Titles do not clear themselves, but every time your TITLE statement executes it will clear any existing titles.
I modified your code a bit to work on sashelp.prdsale, and it seems fine:
%macro titletest(dummy);
%local i region1 region2;
proc sql noprint;
select distinct region
into :region1 - :region2
from sashelp.prdsale
;
quit;
%put region1=&region1 region2=&region2;
%do i=1 %to 2;
title1 "Results for &&region&i";
proc print data=sashelp.prdsale;
where region="&&region&i";
run;
title1;
%end;
%mend;
options mprint;
%titletest()

SAS-Writing Multiple Tables to one XLSX Workbook w/ 2 tables per sheet

I am new to SAS and am having some issues exporting data. I have written a macro to generate some summary tables based on a certain ID. The macro creates two tables for each ID identified in a particular proc sql query. I can write out the last two tables but it overwrites all tables. I was wondering if there is a way to generate one sheet, containing the two summary tables, for each ID identified in my query. Below is the code I have to date for exporting data:
%macro output(x);
ods tagsets.excelxp file="W:\user\test.xls" options(sheet_interval='none');
proc print data=prov_&x;
run;
proc print data=prov_revcd_&x;
run;
ods tagsets.excelxp close;
%mend;
/*Run a loop for each IDcode. Each code will enter the document generation loop*/
%macro loopit(mylist);
%let else=;
%let n = %sysfunc(countw(&mylist)); /*let n=number of codes in the list*/
data
%do I=1 %to &n;
%let val = %scan(&mylist,&I); /*Let val= the ith code in the list*/
%end;
%do j=1 %to &n;
%let val = %scan(&mylist,&j); /*Let val= the jth code in the list*/
/*Run the macro loop to generate the required tables*/
%runtab(&val);
%output&val);
%end;
run;
%mend;
/*Run the macro loop over the list of significant procedure code values*/
%loopit(&varlist);
Any help for correcting this issue would be greatly appreciated! Thanks!
I would rewrite %output like so.
%macro output(x);
ods tagsets.excelxp options(sheet_interval='none' sheet_name="&x");
proc print data=prov_&x;
run;
proc print data=prov_revcd_&x;
run;
%mend;
Then as Reeza suggests put the original ods tagsets.excelxp file= ... and close outside the whole macro.
ods tagsets.excelxp file="c:\temp\test.xlsx";
%loopit(&varlist)
ods tagsets.excelxp close;
If you use PROC EXPORT, that does allow apending to a workbook without this step (and no ODS at al).
%macro output(x);
proc export data=prov_&x outfile="c:\temp\test.xlsx" dbms=excel replace;
sheet="&x._prov";
run;
%mend;
However, this only allows one dataset per sheet - so either you append them together first as a single dataset, or you use 2 sheets in this solution.
Move the ods tagsets.excelxp file= and ods tagsets.excelxp close to outside of the macro otherwise you're recreating the file each time.
You may want to explicitly name the sheets as well.

List only the column names of a dataset

I am working on SAS in UNIX env and I want to view only the column name of a dataset. I have tried proc contents and proc print but both of them list a lot of other irrevelant information that I do not want as it fills up my putty screen and the information ultimately is lost.
I also tried to get this thing frm the sas metadata but that is not working either.
I tried :
2? proc sql;
select *
from dictionary.tables
where libname='test' and memname='sweden_elig_file_jul';
quit;
5?
NOTE: No rows were selected.
6?
NOTE: PROCEDURE SQL used (Total process time):
real time 0.27 seconds
cpu time 0.11 seconds
You're using the wrong dictionary table to get column names...
proc sql ;
select name
from dictionary.columns
where memname = 'mydata'
;
quit ;
Or using PROC CONTENTS
proc contents data=mydata out=meta (keep=NAME) ;
run ;
proc print data=meta ; run ;
Here's one I've used before to get a list of columns with a little bit more information, you can add the keep option as in the previous answer. This just demonstrates how to create a connection to the metadata server, in case that is useful to anyone viewing this post.
libname fetchlib meta
library="libraryName" metaserver="metaDataServerAddress"
password="yourPassword" port=1234
repname="yourRepositoryName" user="yourUserName";
proc contents data=fetchlib.YouDataSetName
memtype=DATA
out=outputDataSet
nodetails
noprint;
run;
For a pure macro approach, try the following:
%macro mf_getvarlist(libds
,dlm=%str( )
)/*/STORE SOURCE*/;
/* declare local vars */
%local outvar dsid nvars x rc dlm;
/* open dataset in macro */
%let dsid=%sysfunc(open(&libds));
%if &dsid %then %do;
%let nvars=%sysfunc(attrn(&dsid,NVARS));
%if &nvars>0 %then %do;
/* add first dataset variable to global macro variable */
%let outvar=%sysfunc(varname(&dsid,1));
/* add remaining variables with supplied delimeter */
%do x=2 %to &nvars;
%let outvar=&outvar.&dlm%sysfunc(varname(&dsid,&x));
%end;
%End;
%let rc=%sysfunc(close(&dsid));
%end;
%else %do;
%put unable to open &libds (rc=&dsid);
%let rc=%sysfunc(close(&dsid));
%end;
&outvar
%mend;
Usage:
%put List of Variables=%mf_getvarlist(sashelp.class);
Returns:
List of Variables=Name Sex Age Height Weight
source: https://github.com/sasjs/core/blob/main/base/mf_getvarlist.sas
proc sql;
select *
from dictionary.tables
where libname="TEST" and memname="SWEDEN_ELIG_FILE_JUL";
quit;