Using upcase function in SAS programming? - sas

Very new to SAS programming 0.0
I am trying to change the title "Listing of Data Set Health" to all uppercase and what I am doing isn't working. PLS HELP.
proc format;
value $Gender
'M'='Male'
'F'='Female'
other= 'Unknown'; * Handle Missing Values;
run;
data health;
infile '/folders/myfolders/health.txt' pad;
input #1 Subj $3.
#4 Gender $1.
#5 (Age HR) (2.)
#9 (SBP DBP Chol) (3.);
if Chol gt 200 then do;
Stoke_Risk = 'High';
LDL_Group = 'Bad';
end;
if Age le 21 then Age_Group = 1;
else if Age le 59 then Age_Group = 2;
else if Age ge 60 then Age_Group = 3;
format Gender $Gender.; *this line could be under data or proc
print;
Current_Year = year(today()); *current year based on today and year function;
Short_Gender = lowcase(Gender); *lower case function for string;
ABP = mean(SBP, DBP); *mean of blood pressure;
run;
title "Listing of Data Set Health";
proc print data=health;
ID Subj;
run;

The title statement is a global statement that is used in open code. If you would like it to always be upper-case, you will want to type your title directly in upper-case:
title "LISTING OF DATA SET HEALTH";
If you want to be able to have it always be in upper-case no matter what you type, you will need to delve into the SAS Macro Facility and macro functions. This is a more advanced aspect of SAS that you will get into later.
The %upcase() macro function can be used in open code to convert any text to upper-case.
title "%upcase(listing of data set health)";
Note that this function differs from upcase(), which you will use in the data step. Functions starting with % are special macro functions.

You can explicitly change it to uppercase in the title statement:
title "LISTING OF DATA SET HEALTH";
If you want to change the title dynamically, you could write a macro like:
%let title = "Listing of Data Set Health";
title "%upcase(&title.)";

Related

Print values in a PROC IML

This is a dataset that I am using.
data have;
input name $char17.; datalines;
Abdallah
Abou Hanna
Afonso
Angre
Audepart
Bah Aicha
Baudras
Berthelot
;
This consists of just one variable which has some names in it. I have to create a macro in SAS which I have named RAN_NAMES. I have to enter a NUM and then it will print that amount of names. The problem that I am facing is that I have to print the names using a macro variable '&NAME' using a DO loop in different lines. And with them I have to print the dates.
So I don't know how to create a macro character variable because inside IML only a matrix is returned.
%MACRO RAN_NAMES(NUM);
PROC IML;
varnms = {"nom"};
USE WORKK.NOMS;
READ ALL VAR varnms INTO NAMES;
CLOSE WORKK.NOMS;
N = NROW(NAMES);
IF &NUM. > N THEN DO; PRINT "Maximum number of names exceeded. You can enter more than 41"; ABORT; END;
ELSE DO;
SAM = SAMPLE(NAMES, &NUM.);
END;
QUIT;
%MEND RAN_NAMES;

SAS Proc Report banded rows with skipped line

I am using PROC REPORT to generate an output. I need banded lines of alternate colours and am able to achieve this by incrementing a counter variable and testing to see if the row number is odd or even, this works as expected. I am also using a compute block to add a blank line after each group of order variables. I would like the background colour of the blank line to also be determined by the value of the counter variable, but this doesn't seem to be possible. I do not want to go down the route of adding the blank line to the dataset before running PROC REPORT, is there a solution. Please find code below:
PROC REPORT DATA = sashelp.class NOWD SPLIT = "!" HEADLINE HEADSKIP MISSING ;
COLUMN sex name ;
DEFINE sex / ORDER ;
***this adds banding to the rows and works as expected ***;
COMPUTE name;
count+1;
IF MOD(count, 2) gt 0 THEN DO;
CALL DEFINE(_ROW_,'STYLE','style=[background=red]');
END;
ELSE DO;
CALL DEFINE(_ROW_,'STYLE','style=[background=green]');
END;
ENDCOMP;
***section adds a blank line and I can control the background colour but I can t assign this colour based on the value of the count variable ***;
COMPUTE AFTER sex / style=[background=blue] ;
LINE " " ;
ENDCOMP;
RUN;
There is always the old way:
proc sort data = sashelp.class out = test;
by sex;
run;
data test;
set test;
by sex;
output;
if last.sex then do;
call missing(name);
output;
end;
run;
proc report data = test;
column sex name ord;
define sex /order order = data;
define ord /noprint;
compute name;
count + 1;
if mod(count, 2) then do;
call define(_row_,'style','style=[background=green]');
end;
else do;
call define(_row_,'style','style=[background=red]');
end;
endcomp;
run;
If you can solve it just by modifying an option, please share your skill.

SAS way of R's cut function [duplicate]

I have the numeric values of salaries of different employee's. I want to break the ranges up into categories. However I do not want a new column rather, I want to just format the existing salary column into this range method:
At least $20,000 but less than $100,000 -
At least $100,000 and up to $500,000 - >$100,000
Missing - Missing salary
Any other value - Invalid salary
I've done something similar with gender. I just want to use the proc print and format command to show salary and gender.
DATA Work.nonsales2;
SET Work.nonsales;
RUN;
PROC FORMAT;
VALUE $Gender
'M'='Male'
'F'='Female'
'O'='Other'
other='Invalid Code';
PROC FORMAT;
VALUE salrange
'At least $20,000 but less than $100,000 '=<$100,000
other='Invalid Code';
PROC PRINT;
title 'Salary and Gender';
title2 'for Non-Sales Employees';
format gender $gender.;
RUN;
Proc Format is the correct method and you need a numeric format:
proc format;
value salfmt
20000 - <100000 = "At least $20,000 but less than $100,000"
100000 - 500000 = "100,000 +"
. = 'Missing'
other = 'Other';
Then in your print apply the format, similar to what you did for gender.
format salary salfmt.;
This should help get you started.
I created a little function that mimics the R cut functions :
options cmplib=work.functions;
proc fcmp outlib=work.functions.test;
function cut2string(var, cutoffs[*], values[*] $) $;
if var <cutoffs[1] then return (values[1]);
if var >=cutoffs[dim(cutoffs)] then return (values[dim(values)]);
do i=1 to dim(cutoffs);
if var >=cutoffs[i] & var <cutoffs[i+1] then return (values[i+1]);
end;
return ("Error, this shouldn't ever happen");
endsub;
run;
Then you can use it like this :
data Work.nonsales2;
set Work.nonsales;
array cutoffs[3] _temporary_ (20000 100000 500000);
array valuesString[4] $10 _temporary_ ("<20k " "20k-100k" "100k-500k" ">500k");
salary_string = cut2string(salary ,cutoffs,valuesString);
run;

Suppress Subtotal in Proc report

I have a proc report that groups and does subtotals. If I only have one observation in the group, the subtotal is useless. I'd like to either not do the subtotal for that line or not do the observation there. I don't want to go with a line statement, due to inconsistent formatting\style.
Here's some sample data. In the report the Tiki (my cat) line should only have one line, either the obs from the data or the subtotal...
data tiki1;
name='Tiki';
sex='C';
age=10;
height=6;
weight=9.5;
run;
data test;
set sashelp.class tiki1;
run;
It looks like you are trying do something that proc report cannot achieve in one pass. If however you just want the output you describe here is an approach that does not use proc report.
proc sort data = test;
by sex;
run;
data want;
length sex $10.;
set test end = eof;
by sex;
_tot + weight;
if first.sex then _stot = 0;
_stot + weight;
output;
if last.sex and not first.sex then do;
Name = "";
sex = "Subtotal " || trim(sex);
weight = _stot;
output;
end;
keep sex name weight;
if eof then do;
Name = "";
sex = "Total";
weight = _tot;
output;
end;
run;
proc print data = want noobs;
run;
This method manually creates subtotals and a total in the dataset by taking rolling sums. If you wanted do fancy formatting you could pass this data through proc report rather than proc print, Joe gives an example here.

SAS put variable format in title

I have a variable called agegroup which has many categories, eg: 1="0-5" 2="6-10" etc.
If I create a macro to print data by agegroup and wanted to have age group format in the title, how can I do this?
%macro ageprint(agegrp=1);
proc print data=age;
title "Age group &agegrp";
run;
%mend;
if I run this macro I would like the title be printed as "Age group 0-5" instead of "age group 1".
Anyone has hints?
Thanks!
You can use the #byval(age) option as well, it takes on the formatted value in the title:
proc format ;
value grpformat
0 - 12 = '0 - 12'
12 - 14 = '12 - 14'
other = 'other'
;
run;
proc sort data=sashelp.class out=class; by age; run;
proc print data=class;
by age;
format age grpformat.;
title "Age Group #byval(age)";
run;
You can still use the same method if you need a macro to control where the output was going for example:
%macro ageprint(agegrp=1);
proc print data=age;
by agegrp;
title "Age group #byval(agegrp)";
run;
%mend;
Something like this?
proc format ;
value grpformat
0 - 5 = '0 - 5'
6 - 10 = '6 - 10'
other = 'other'
;
run;
%macro ageprint(agegrp);
proc print data=age;
where agegrp=&agegrp;
title "Age group %sysfunc(putn(&agegrp, grpformat.))";
run;
%mend;
%ageprint(agegrp=2);
%ageprint(agegrp=8);