SAS distinct level - macros

data test1;
input var1$ var2$ ;
datalines;
1 a
2 a
3 a
1 b
2 b
1 c
;
run;
How can I create a macro var that contains all levels of var2?
For example:
%Let new_var = a b c;

If I understood the question correctly, I think you can try using proc sql for this.
proc sql;
select distinct var2 into :new_var from test1;
quit;

Related

SAS Select Into Dynamic Naming

I am trying to use SAS proc sql select into for 8 different scenarios.
%MACRO Loop();
proc sql;
%do i=1 %to 8;
select total_value
into :Sol_&i. separated by ','
from Master.adjusted_hours
where Solicitation = "&i.";
%end;
quit;
%mend;
%Loop();
However when I use the %put function, the macro variable isn't recognized. The error is "Apparent symbolic reference SOL_1 not resolved."
%put &Sol_1;
How can I store the value in this macro variable and call it later in the code?
You need to declare SOL_1 SOL_2, etc as global macro variables. I wasn't sure what was in your data, so I created some dummy data.
%global SOL_1 SOL_2 SOL_3 SOL_4 SOL_5 SOL_6 SOL_7 SOL_8;
data adjusted_hours;
do x = 1 to 8;
solicitation=put(x, 1.);
do total_value = 1 to 10;
output;
end;
end;
drop x;
run;
%MACRO Loop();
proc sql noprint;
%do i = 1 %to 8;
select total_value
into : Sol_&i. separated by ','
from adjusted_hours
where Solicitation = "&i.";
%end;
quit;
%mend;
%Loop();
%put _USER_;
Partial log:
GLOBAL SOL_1 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_2 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_3 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_4 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_5 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_6 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_7 1,2,3,4,5,6,7,8,9,10
GLOBAL SOL_8 1,2,3,4,5,6,7,8,9,10
If you want to avoid the macro altogether and having to declare the %global variables, here's a data step solution that will work as long as your dataset is sorted by Solicitation.
data _null_;
set adjusted_hours;
by solicitation;
format temp $50.;
retain temp ;
temp=CATX(',',temp, total_value);
if last.solicitation then do;
call symputx(CATS('SOL_', solicitation), temp);
call missing(temp);
end;
run;

How do I get Sas Dataset Headers to export to excel sheet via DDE

So I am trying to write a macro which exports my sas dataset to an existing excel sheet. I am using the following code which I found from one of the SUGI papers. The problem is that the following code does the job successfully, but it just can not copy paste the headers(variable names) to the excel and just pastes all the observations. How do I get my code to also paste the headers(variable names) to the excel
%MACRO EXCELOUT(SDS=,XLSSHT=,XLSF=, ROW=,COL= ) ;
PROC CONTENTS DATA=&SDS NOPRINT OUT=CNT ;
RUN;
PROC SORT DATA=CNT ;
BY VARNUM ;
RUN;
PROC SQL NOPRINT;
SELECT NAME
INTO: VARS SEPARATED BY ' '
FROM CNT ;
SELECT COUNT(DISTINCT NAME)
INTO: COLS SEPARATED BY ' '
FROM CNT ;
SELECT NOBS
INTO: ROWS
FROM CNT
WHERE VARNUM = 1;
QUIT;
OPTIONS NOXWAIT NOXSYNC ;
X "&XLSF" ;
DATA _NULL_ ;
X=SLEEP(5);
RUN ;
FILENAME TEMP DDE "EXCEL|&XLSSHT.!R&ROW.C&COL.:R%TRIM(%EVAL(&ROWS+&ROW1))C%TRIM(%EVAL(&COLS+&COL)" ;
DATA _NULL_ ;
SET &SDS ;
FILE TEMP ;
PUT &VARS ;
RUN ;
FILENAME CMDS DDE 'EXCEL|SYSTEM' ;
DATA _NULL_ ;
FILE CMDS ;
PUT '[SAVE()]' ;
PUT '[QUIT()]' ;
RUN ;
%MEND EXCELOUT ;
Just add a little more logic to the step that writes the data to have it write the names also.
data _null_ ;
file temp ;
if _n_=1 then do;
do _n_=1 to &cols ;
set cnt(keep=name rename=(name=__name__)) ;
put __name__ #;
end;
put;
end;
set &sds ;
put &vars ;
run ;
Your code to get the variable names and count the rows and columns could be simpler also.
proc sql noprint;
select nobs
, name
into :rows trimmed
, :vars separated by ' '
from cnt
;
%let cols = &sqlobs ;
quit;
Your FILENAME statement does not need %TRIM(), and was missing the + needed to add one row for the header. Made it look like it was referencing &row1 instead of &row.
filename temp dde "excel|&xlssht.!r&row.c&col.:r%eval(&rows+&row+1)c%eval(&cols+&col)" ;

How to add a column containing mean value to a table in SAS

Assume this is my dataset:
data test;
input Age ;
datalines;
34
28
27
36
32
39
12
32
;
How can I add a column to this dataset which contains the average value of the age column?
Use PROC SQL;
proc sql;
create table test2 as
select age,
mean(age) as age_mean
from test;
quit;
Without a GROUP BY statement, SQL will merge the mean back with the original values.
It is easy to get it with proc sql.
proc sql;
select *,mean(age) as Age_mean from test;
quit;

symbolic reference in MACRO IN sas

I have been recieving an error- symbolic reference not resolved when i run the macro in sas using following code:
Initially I select as set of Role Numbers using SQL into a list as:
PROC SQL NOPRINT; SELECT ROLENO INTO:R1-:R81 FROM ROLLNOS; QUIT;
Then a macro is used to select each individual marks and conoslidate them as :
options Mprint;
%MACRO Marks;
%DO I=1 %TO 1;
proc sql noprint;
create table Marks as select name, rollno, marks, grade from masterdata
where rollno= "&R&I.";
quit;
PROC APPEND DATA=Marks BASE=MarksSheet FORCE;RUN;
%END;
%MEND;
RUN;
%Marks;
I got an error when the sql statement is executed, Please help me resolve the issue. especially with referencing part- "&R&I."
You want to resolve to R1.
&R&I. resolves to macarovariable R (which is not available) and macrovariable I.
You need a second & before the R, because 2 & resolve to one.
If you use &&R&I, in the first step &&R resolves to &R and &I resolves to 1, so you got &R1. This will then resolve to the macrovariable R1 in second step.
Also %do I=1 %to 1 only has one iteration, is this meant to be?
options Mprint;
%MACRO Marks;
%DO I=1 %TO 1;
proc sql noprint;
create table Marks as select name, rollno, marks, grade from masterdata
where rollno= "&&R&I.";
quit;
PROC APPEND DATA=Marks BASE=MarksSheet FORCE;RUN;
%END;
%MEND;
%Marks;

How to store the distinct values of a variable in macro variable(s)

I have a group macro variable, I would like to make its classes in to macro vars. For example:
%macro test(group=);
proc freq data=foll;
tables &group / out=freqtbl;
run;
proc sql;
create table grp
(grpid char(4));
insert into grp
values('a')
values('b')
;
quit;
data freqtbl1;
merge grp freqtbl;
run;
data freqtbl2;
set freqtbl1;
call symput(grpid,&group);
run; * &a is the first group, &b is the second group;
%mend;
This works for 2 classes, but what if it has 3 or more than 3 classes?
Thanks a lot.
proc sql;
select distinct age into :cls1-:cls10
from sashelp.class;
quit;
%put &cls1 &cls2 &cls3 &cls4 &cls5 &cls6 &cls7;
You'll still have the issue of knowing when to stop when using this (like in the above, &cls7 is not resolved). Set the -:cls10 or whatever to a high enough value you don't run out of variables.
If you actually would prefer this to be in one variable,
select distinct age into :cls separated by ' '
would make &cls that has all of the values in it.
You could also do this in the data step - something like:
data _null_;
set mydata;
by myvar;
initialvar=65;
if first.myvar then do;
call symput(byte(initialvar),myvar);
initialvar+1;
end;
run;
This would require you to have it sorted. You could alternately run a similar set of code off of the PROC FREQ result dataset.
This macro will create a macro variable for each distinct observation in a column for a dataset.
Var=the column you want a set of macro variables for
dataset= the dataset you have the column in
%macro var_for_val(dataset=,var=);
proc sql noprint;
create table dist_var as
select distinct &var.
from &dataset.
;
quit;
proc sql noprint;
create table dist_Var2 as
select monotonic() as id, &var.
from dist_var
;
quit;
proc sql noprint;
select distinct max(id)
into :max_var
from dist_var2
;
quit;
%do i = 1 %to &max_var.;
%global var_&i.;
proc sql noprint;
select distinct &var.
into :var_&i.
from dist_var2
where id = &i.
;
quit;
%put &&var_&i.;
%end;
%mend;
%var_for_val(sashelp.class,var=age);
%put &var_1.;