Macros for SAS Application Developers
https://github.com/sasjs/core
mp_hashdataset.sas
Go to the documentation of this file.
1 /**
2  @file
3  @brief Returns a unique hash for a dataset
4  @details Ignores metadata attributes, used only to hash values. If used to
5  compare datasets, they must have their columns and rows in the same order.
6 
7  %mp_hashdataset(sashelp.class,outds=myhash)
8 
9  data _null_;
10  set work.myhash;
11  put hashkey=;
12  run;
13 
14  ![sas md5 hash dataset log results](https://i.4gl.io/1/KorUKoyE05.png/raw)
15 
16  <h4> SAS Macros </h4>
17  @li mf_getattrn.sas
18  @li mf_getuniquename.sas
19  @li mf_getvarlist.sas
20  @li mp_md5.sas
21 
22  <h4> Related Files </h4>
23  @li mp_hashdataset.test.sas
24  @li mp_hashdirectory.sas
25 
26  @param [in] libds dataset to hash
27  @param [in] salt= () Provide a salt (could be, for instance, the dataset name)
28  @param [in] iftrue= (1=1) A condition under which the macro should be executed
29  @param [out] outds= (work._data_) The output dataset to create. This
30  will contain one column (hashkey) with one observation (a $hex32.
31  representation of the input hash)
32  |hashkey:$32.|
33  |---|
34  |28ABC74ABFC45F50794237BA5566E6CA|
35 
36  @version 9.2
37  @author Allan Bowe
38 **/
39 
40 %macro mp_hashdataset(
41  libds,
42  outds=work._data_,
43  salt=,
44  iftrue=%str(1=1)
45 )/*/STORE SOURCE*/;
46 
47 %local keyvar /* roll up the md5 */
48  prevkeyvar /* retain prev record md5 */
49  lastvar /* last var in input ds */
50  cvars nvars;
51 
52 %if not(%eval(%unquote(&iftrue))) %then %return;
53 
54 /* avoid naming conflict for hash key vars */
55 %let keyvar=%mf_getuniquename();
56 %let prevkeyvar=%mf_getuniquename();
57 %let lastvar=%mf_getuniquename();
58 
59 %if %mf_getattrn(&libds,NLOBS)=0 %then %do;
60  data &outds;
61  length hashkey $32;
62  hashkey=put(md5("&salt"),$hex32.);
63  output;
64  stop;
65  run;
66  %put &sysmacroname: Dataset &libds is empty, or is not a dataset;
67  %put &sysmacroname: hashkey of &outds is based on salt (&salt) only;
68 %end;
69 %else %if %mf_getattrn(&libds,NLOBS)<0 %then %do;
70  %put %str(ERR)OR: Dataset &libds is not a dataset;
71 %end;
72 %else %do;
73  data &outds(rename=(&keyvar=hashkey) keep=&keyvar)
74  %if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5" %then %do;
75  /nonote2err
76  %end;
77  ;
78  length &prevkeyvar &keyvar $32;
79  retain &prevkeyvar;
80  if _n_=1 then &prevkeyvar=put(md5("&salt"),$hex32.);
81  set &libds end=&lastvar;
82  /* hash should include previous row */
83  &keyvar=%mp_md5(
84  cvars=%mf_getvarlist(&libds,typefilter=C) &prevkeyvar,
85  nvars=%mf_getvarlist(&libds,typefilter=N)
86  );
87  &prevkeyvar=&keyvar;
88  if &lastvar then output;
89  run;
90 %end;
91 %mend mp_hashdataset;