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;