You suffer from a bad dataset structure, causing you to use name literals, waste space for missing values, and write bad code.
First, transpose your dataset to a long layout:
options validvarname=any;
data have;
input
ID SURVEY
"1Q1"n "1Q2"n "1Q3"n "2Q1"n "2Q2"n "3Q1"n "3Q2"n "3Q3"n "3Q4"n "3Q5"n
"4Q1"n "4Q2"n "4Q3"n "4Q4"n "5Q1"n "5Q2"n "5Q3"n
;
datalines;
1 1 1 2 3 . . . . . . . . . . . . . .
1 2 . . . 8 0 . . . . . . . . . . . .
1 3 . . . . . 4 0 1 5 2 . . . . . . .
1 4 . . . . . . . . . . 1 4 2 1 . . .
1 5 . . . . . . . . . . . . . . 1 3 1
2 1 0 3 6 . . . . . . . . . . . . . .
2 2 . . . 7 1 . . . . . . . . . . . .
2 3 . . . . . 5 1 1 5 3 . . . . . . .
2 5 . . . . . . . . . . . . . . 0 2 0
3 1 1 3 3 . . . . . . . . . . . . . .
3 2 . . . 6 0 . . . . . . . . . . . .
3 3 . . . . . 3 1 0 5 1 . . . . . . .
3 4 . . . . . . . . . . 1 4 2 1 . . .
3 5 . . . . . . . . . . . . . . 0 3 1
4 1 1 1 5 . . . . . . . . . . . . . .
4 2 . . . 4 0 . . . . . . . . . . . .
4 3 . . . . . 6 0 1 5 2 . . . . . . .
5 1 0 3 4 . . . . . . . . . . . . . .
5 3 . . . . . 9 0 0 4 1 . . . . . . .
5 4 . . . . . . . . . . 1 4 2 0 . . .
5 5 . . . . . . . . . . . . . . 1 3 1
;
proc transpose
data=have
out=l1 (
rename=(col1=answer)
where=(answer ne .)
)
;
by id survey;
var "1Q1"n--"5Q3"n;
run;
data long;
set l1;
surv = input(scan(_name_,1,"Q"),best.);
question = input(scan(_name_,2,"Q"),best.);
if surv ne survey then putlog "ERROR";
keep id survey question answer;
run;
In the resulting dataset, it is easy to group by (or select for) ID's, surveys, questions.
For reporting purposes, you can use the question as an ACROSS variable in proc report to create a wide layout.
For processing, a long layout is always preferred.
... View more