Format Data Set from Parent/Child Links
/****************************************************************/
/* S A S S A M P L E L I B R A R Y */
/* */
/* NAME: ISHLINK */
/* TITLE: Format Data Set from Parent/Child Links */
/* PRODUCT: QC */
/* SYSTEM: ALL */
/* KEYS: Ishikawa Diagrams, */
/* PROCS: ISHIKAWA */
/* DATA: */
/* */
/* MISC: %ISHALVL adds the _LEVEL_ variable to the input */
/* data set. */
/* */
/* %ISHSORT organizes the observations into the */
/* proper order. %ISHSORT does not rely on output */
/* from %ISHALVL so it can be used any time an */
/* Ishikawa data set becomes 'unorderly'. */
/* */
/* These macros do not check the parent/arrow links */
/* for errors. */
/* */
/****************************************************************/
options ps=60 ls=80;
%macro ishalvl( data, arrow, parent );
/* DATA input data set */
/* ARROW arrow variable */
/* PARENT parent variable */
/* Output saved in WORK.ISHIKAWA */
proc sort data=&data out=work;
by &arrow;
run;
data work;
set work;
by &arrow;
if first.&arrow then
output;
else
put 'Warning: Duplicates deleted.';
run;
data work;
set work;
if &parent=' ' then blevel=0;
run;
%do level=1 %to 9;
proc sort data=work;
by &parent;
run;
data subset;
set work;
elevel = &level;
if blevel = elevel-1 then output;
keep &arrow elevel;
run;
proc sort data = subset;
by &arrow;
run;
%let done=0;
data work;
merge work (rename=(&parent=key) in=in)
subset(rename=(&arrow=key));
by key;
if elevel ^= ' ' then blevel = elevel;
if &done = 0 and blevel = ' ' then
call symput('done', '1');
if in then output;
rename key = &parent;
drop elevel;
run;
%if &done=0 %then %let level = 10;
%end;
/* To replace the input data set: change ishikawa to &data */
data ishikawa;
set work;
rename blevel = _level_;
if 0 <= blevel & blevel <= 9;
run;
%mend;
%macro ishsort( data, arrow, parent );
/* DATA input data set */
/* ARROW arrow variable */
/* PARENT parent variable */
/* Output saved in WORK.ISHIKAWA */
data level0 level1 level2 level3 level4
level5 level6 level7 level8 level9;
set &data end=end;
retain max;
drop max;
max = max( max, _level_ );
if _level_ = 0 then output level0;
else if _level_ = 1 then output level1;
else if _level_ = 2 then output level2;
else if _level_ = 3 then output level3;
else if _level_ = 4 then output level4;
else if _level_ = 5 then output level5;
else if _level_ = 6 then output level6;
else if _level_ = 7 then output level7;
else if _level_ = 8 then output level8;
else if _level_ = 9 then output level9;
if end then call symput( 'first', max );
run;
%let first=%left(&first);
data level&first;
set level&first;
key = &parent;
run;
%do i=&first %to 1 %by -1;
proc sort data=level&i;
by key;
run;
%let j=%eval(&i-1);
data level&j;
set level&j;
key = &arrow;
run;
proc sort data=level&j;
by key;
run;
data level&j;
set level&j(in=in) level&i;
by key;
if in then temp=&parent;
retain temp;
drop key;
rename temp=key;
run;
%end;
/* To replace the input data set: change ishikawa to &data */
data ishikawa;
set level0;
drop key;
run;
%mend;
data one; /* input data set */
length a b _text1_ $ 2;
input a b _text1_; /* B is A's parent */
cards;
C8 B3 c
B1 A0 b
G1 F1 g
B2 A0 b
C5 B1 c
E1 D1 e
C9 B1 c
B3 A0 b
C7 B2 c
A0 . a
C1 B2 c
C3 B2 c
C2 B1 c
D1 C1 d
C4 B3 c
F1 E1 f
C6 B3 c
;
%ishalvl( one, a, b ); /* compute values for _LEVEL_ */
%ishsort( ishikawa, a, b ); /* sort into proper order */
proc ishikawa data=ishikawa;
run;