39 %MACRO assertForeignKey (i_mstrLib =
47 ,o_maxObsRprtFail = MAX
49 ,o_treatMissings = VALUE
50 ,i_desc = Check
for foreign key relation
54 %LOCAL l_dsMstrName l_dsLookupName l_MstrVars l_LookupVars l_renameLookup l_actual l_helper l_helper1 l_vartypMstr
55 l_vartypLookup l_rc l_result l_cnt1 l_cnt2 l_casid l_tstid l_path i l_listingVars num_missing l_treatMissings
56 l_treatMissing l_unique l_errMsg;
59 %LET l_dsMstrName = &i_mstrLib..&i_mstMem.;
60 %LET l_dsLookupName = &i_lookupLib..&i_lookupMem.;
61 %LET i_mstKey = %SYSFUNC(compbl(&i_mstKey.));
62 %LET i_lookupKey = %SYSFUNC(compbl(&i_lookupKey.));
63 %LET l_listingVars = %SYSFUNC(COMPBL(&o_listingVars. %str( )));
64 %LET l_treatMissings = %SYSFUNC(upcase(&o_treatMissings.));
65 %LET l_unique = %SYSFUNC(upcase(&i_unique.));
70 %IF &g_inTestcase EQ 1 %THEN %DO;
73 %ELSE %IF &g_inTestcase NE 2 %THEN %DO;
74 %PUT &g_error.(SASUNIT): assert must be called after initTestcase;
78 %*************************************************************;
79 %*** Check preconditions ***;
80 %*************************************************************;
82 %*** check
for valid librefs und existence of data sets Master und Lookup***;
83 %IF ((%SYSFUNC (libref (&i_mstrLib.)) NE 0) or (%SYSFUNC(exist(&l_dsMstrName)) EQ 0)) %THEN %DO;
85 %LET l_errMsg =Libref of master table not valid or data set does not exist;
88 %IF ((%SYSFUNC (libref (&i_lookupLib.)) NE 0) or (%SYSFUNC(exist(&l_dsLookupName)) EQ 0)) %THEN %DO;
90 %LET l_errMsg =Libref of lookup table not valid or data set does not exist;
94 %*** Is the number of keys specified in i_cmpKeyLen the same as actually specified in i_mstKey and i_lookupKey***;
95 %LET l_helper = %eval(%SYSFUNC(count(&i_mstKey,%str( )))+1);
96 %IF (&l_helper. NE &i_cmpKeyLen.) %THEN %DO;
98 %LET l_errMsg =Number of keys found in i_mstKey not compatible to specified number;
101 %LET l_helper = %eval(%SYSFUNC(count(&i_lookupKey,%str( )))+1);
102 %IF (&l_helper. NE &i_cmpKeyLen.) %THEN %DO;
104 %LET l_errMsg =Number of found keys in i_lookupKey not compatible to specified number;
108 %*** Extract given keys to local variables***;
109 %DO i=1 %TO &i_cmpKeyLen.;
110 %local l_mstKey&i l_lookupKey&i;
111 %LET l_mstKey&i = %SYSFUNC(scan(&i_mstKey, &i.,
" "));
112 %LET l_lookupKey&i = %SYSFUNC(scan(&i_lookupKey, &i.,
" "));
115 %*** Check
if parameter o_maxObsRprtFail is valid ***;
116 %IF NOT (%SYSFUNC(upcase(&o_maxObsRprtFail.)) = MAX) %THEN %DO;
117 %IF (%datatyp(&o_maxObsRprtFail.) ~=NUMERIC) %THEN %DO;
119 %LET l_errMsg =%bquote(Parameter o_maxObsRprtFail (&o_maxObsRprtFail): MAX or numeric GE 0);
122 %ELSE %IF (&o_maxObsRprtFail. < 0) %THEN %DO;
124 %LET l_errMsg =%bquote(Parameter o_maxObsRprtFail(&o_maxObsRprtFail) < 0);
129 %*** Check existence of specified keys in their respective tables***;
130 %*** open specified tables ***;
131 %LET l_dsMstid = %SYSFUNC(open(&l_dsMstrName.));
132 %LET l_dsLookupid = %SYSFUNC(open(&l_dsLookupName.));
133 %*** opened correctly? ***;
134 %IF (&l_dsMstid. EQ 0 or &l_dsLookupid. EQ 0) %THEN %DO;
136 %LET l_errMsg =Open
function failed;
140 %*** loop through all variables ***;
141 %DO i=1 %TO &i_cmpKeyLen.;
142 %LET l_helper = %SYSFUNC(varnum(&l_dsMstid., &&l_mstKey&i.));
143 %IF &l_helper. = 0 %THEN %DO;
144 %* specified variable not found;
146 %LET l_errMsg =Key in master table not found;
150 %* specified variable found:
get variable type;
151 %LET l_vartypMstr = %SYSFUNC(vartype(&l_dsMstid., &l_helper.));
153 %*** Concatenate String
for sql where condition: find missing values ***;
154 %IF &l_vartypMstr. =N %THEN %DO;
155 %LET l_helper1 = %str(.);
158 %LET l_helper1 = %str(
"");
160 %*** Insert or into sql where condition
if loop runs more than once ***;
161 %IF &i > 1 %THEN %DO;
162 %LET l_treatMissing = &l_treatMissing. OR;
164 %LET l_treatMissing = &l_treatMissing. &&l_mstKey&i. %str(=) &l_helper1;
167 %LET l_helper = %SYSFUNC(varnum(&l_dsLookupid.,&&l_lookupKey&i.));
168 %IF (&l_helper. EQ 0) %THEN %DO;
169 %* specified variable not found;
171 %LET l_errMsg = Key in lookup table not found;
175 %* specified variable found:
get variable type;
176 %LET l_vartypLookup = %SYSFUNC(vartype(&l_dsLookupid., &l_helper.));
180 %IF (&l_vartypMstr. NE &l_vartypLookup.) %THEN %DO;
181 %* specified variable not found;
183 %LET l_errMsg =Variable types of keys in master and lookup table
do not match;
188 %*** loop through l_listingVars: Check
if valid ***;
190 %LET l_helper1 = %SYSFUNC(scan(&l_listingVars., &i., %str( )));
192 %DO %UNTIL (&l_helper1=%str( ));
193 %IF (&l_helper1. =) %THEN %DO;
196 %LET l_helper = %SYSFUNC(varnum(&l_dsMstid., &l_helper1.));
197 %IF &l_helper. = 0 %THEN %DO;
198 %* specified variable not found;
200 %LET l_errMsg =%bquote(Parameter o_listingVars (&l_listingVars) not found in Master Table);
203 %LET i = %eval(&i+1);
204 %LET l_helper1 = %SYSFUNC(scan(&l_listingVars., &i., %str( )));
207 %LET l_listingVars= &i_mstKey. &l_listingVars.;
208 %LET l_rc=%SYSFUNC(close(&l_dsMstid.));
209 %LET l_rc=%SYSFUNC(close(&l_dsLookupid.));
211 %*** parameter l_treatMissings: handle different cases ***;
212 %*** make local copy of master table*;
217 %*** check
for valid parameters*;
218 %IF (&l_treatMissings. NE IGNORE AND &l_treatMissings. NE DISALLOW AND &l_treatMissings. NE VALUE) %THEN %DO;
220 %LET l_errMsg = %bquote(Invalid argument für parameter treatMissings (&l_treatMissings));
224 %***
get number of missing keys in master table*;
226 create table master_missing as
229 where &l_treatMissing.;
233 %***
get number of observations ***;
234 %LET l_helper =%SYSFUNC(open(master_missing));
235 %LET num_missing =%SYSFUNC(attrn(&l_helper,nlobs));
236 %LET l_rc =%SYSFUNC(close(&l_helper));
238 %*** Exit
if missings were found***;
239 %IF (
"&l_treatMissings." =
"DISALLOW" AND &num_missing. GT 0) %THEN %DO;
241 %LET l_errMsg = %str(Parameter treatMissingsMst set to disallow, but missings found in master table);
244 %ELSE %IF (
"&l_treatMissings." EQ
"IGNORE") %THEN %DO;
245 %***
delete missing values ***;
248 where &l_treatMissing.;
253 %*** check
for valid parameter i_unique ***;
254 %IF (&l_unique. NE TRUE AND &l_unique. NE FALSE) %THEN %DO;
256 %LET l_errMsg =Value
for parameter i_unique not valid (&l_unique);
260 %*************************************************************;
261 %*** start tests ***;
262 %*************************************************************;
264 %*** Get distinct values from lookup table***;
265 %DO i=1 %to &i_cmpKeyLen.;
266 %IF (&i>1) %THEN %DO;
267 %*** Insert comma into sql select clause ***;
268 %LET l_LookupVars = &l_LookupVars. ,;
270 %LET l_MstrVars = &l_MstrVars. &&l_mstKey&i.;
271 %LET l_LookupVars = &l_LookupVars. &&l_lookupKey&i.;
272 %LET l_renameLookup = &l_renameLookup. &&l_lookupKey&i.=&&l_mstKey&i.;
275 %*** Check whether specified key is unique
for lookup table ***;
277 create table distKeysLookUp as
278 SELECT distinct &l_LookupVars.
279 FROM &l_dsLookupName.
283 %*** Count nobs from specified lookup table: May contain duplicate key values***;
285 SELECT count(*) into :l_cnt1
286 FROM &l_dsLookupName.
290 %*** Count nobs in distKeysLookUp: Contains only distinct keys***;
292 SELECT count(*) into: l_cnt2
293 FROM work.distKeysLookUp
297 %*** Is parameter l_unique set to true -> are duplicates allowed? ***;
298 %IF (("&l_unique." EQ "TRUE") AND (&l_cnt1. NE &l_cnt2.)) %THEN %DO;
300 %LET l_errMsg =%str(Specified key of lookup table not unique, check parameter i_unique or lookup table);
303 %*** if parameter l_unique is set to false, put warning to log, but go on processing ***;
304 %ELSE %IF (("&l_unique." EQ "FALSE") AND (&l_cnt1. NE &l_cnt2.))%THEN %DO;
305 %PUT g_warning.(SASUNIT): Parameter i_unique set to false and lookup table not unique;
308 %*** Check whether all keys in the master table are available in the lookup table***;
309 proc sort data = mstrCopy out = mstrSorted;
312 data keyNotFndMstr keyNotFndLookUp;
313 merge mstrSorted(in=fndMstr) distKeysLookUp(in=fndLookUp rename=(&l_renameLookup.));
315 if fndLookUp AND not fndMstr then output keyNotFndMstr;
316 If not fndLookUp AND fndMstr then output keyNotFndLookUp;
319 %*** Who many keys from the master table were not found in the lookup table ***;
320 %LET l_helper =%SYSFUNC(OPEN(work.keyNotFndLookUp,IN));
321 %LET l_actual =%SYSFUNC(ATTRN(&l_helper,NOBS));
322 %LET l_rc =%SYSFUNC(CLOSE(&l_helper));
324 %*** Test successful? l_actual < 0 -> error_message, l_actual > 0 -> no foreign key relationship***;
325 %IF (&l_actual. = 0) %THEN %DO;
329 %IF (&l_actual. > 0) %THEN %DO;
330 %LET l_errMsg = &l_actual. key(s) not found in lookup table;
334 %_getScenarioTestId (i_scnid=&g_scnid, r_casid=l_casid, r_tstid=l_tstid);
336 %*** create subfolder ***;
337 %_createTestSubfolder (i_assertType =assertForeignKey
345 %LET l_helper= %SYSFUNC(getoption(work));
346 libname tar_afk "&l_path.";
347 %IF %SYSFUNC(fileexist(&l_helper./keyNotFndLookUp.sas7bdat)) NE 0 %THEN %DO;
349 data keyNotFndLookUp;
350 set keyNotFndLookUp(OBS=&o_maxObsRprtFail.);
354 proc copy in = work out = tar_afk;
355 select keyNotFndLookUp;
358 %IF %SYSFUNC(fileexist(&l_helper./keyNotFndMstr.sas7bdat)) NE 0 %THEN %DO;
360 set keyNotFndMstr(OBS=&o_maxObsRprtFail.);
364 proc copy in = work out = tar_afk;
365 select keyNotFndMstr;
370 %_asserts(i_type = assertForeignKey
371 ,i_expected = %str(&l_unique.)
372 ,i_actual = %str(&l_actual)
374 ,i_result = &l_result.
375 ,i_errMsg = &l_errMsg.
378 %MEND assertForeignKey;