@sasjs/utils 2.49.0 → 2.49.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fs/internal/helper.js +19 -24
- package/fs/internal/helper.js.map +1 -1
- package/macros/mf_abort.sas +27 -0
- package/macros/mf_dedup.sas +53 -0
- package/macros/mf_deletefile.sas +31 -0
- package/macros/mf_existds.sas +30 -0
- package/macros/mf_existfeature.sas +59 -0
- package/macros/mf_existfileref.sas +33 -0
- package/macros/mf_existfunction.sas +37 -0
- package/macros/mf_existvar.sas +39 -0
- package/macros/mf_existvarlist.sas +56 -0
- package/macros/mf_fmtdttm.sas +42 -0
- package/macros/mf_getapploc.sas +78 -0
- package/macros/mf_getattrc.sas +34 -0
- package/macros/mf_getattrn.sas +34 -0
- package/macros/mf_getengine.sas +54 -0
- package/macros/mf_getfilesize.sas +64 -0
- package/macros/mf_getfmtlist.sas +61 -0
- package/macros/mf_getfmtname.sas +44 -0
- package/macros/mf_getkeyvalue.sas +32 -0
- package/macros/mf_getplatform.sas +75 -0
- package/macros/mf_getquotedstr.sas +57 -0
- package/macros/mf_getschema.sas +43 -0
- package/macros/mf_getuniquefileref.sas +60 -0
- package/macros/mf_getuniquelibref.sas +57 -0
- package/macros/mf_getuniquename.sas +22 -0
- package/macros/mf_getuser.sas +44 -0
- package/macros/mf_getvalue.sas +36 -0
- package/macros/mf_getvarcount.sas +49 -0
- package/macros/mf_getvarformat.sas +72 -0
- package/macros/mf_getvarlen.sas +56 -0
- package/macros/mf_getvarlist.sas +74 -0
- package/macros/mf_getvarnum.sas +58 -0
- package/macros/mf_getvartype.sas +52 -0
- package/macros/mf_getxengine.sas +43 -0
- package/macros/mf_increment.sas +29 -0
- package/macros/mf_isblank.sas +27 -0
- package/macros/mf_isdir.sas +34 -0
- package/macros/mf_isint.sas +36 -0
- package/macros/mf_islibds.sas +40 -0
- package/macros/mf_loc.sas +29 -0
- package/macros/mf_mkdir.sas +67 -0
- package/macros/mf_mval.sas +19 -0
- package/macros/mf_nobs.sas +26 -0
- package/macros/mf_trimstr.sas +50 -0
- package/macros/mf_uid.sas +21 -0
- package/macros/mf_verifymacvars.sas +72 -0
- package/macros/mf_wordsinstr1andstr2.sas +53 -0
- package/macros/mf_wordsinstr1butnotstr2.sas +54 -0
- package/macros/mf_writefile.sas +67 -0
- package/macros/mp_abort.sas +301 -0
- package/macros/mp_appendfile.sas +57 -0
- package/macros/mp_applyformats.sas +181 -0
- package/macros/mp_assert.sas +56 -0
- package/macros/mp_assertcols.sas +145 -0
- package/macros/mp_assertcolvals.sas +168 -0
- package/macros/mp_assertdsobs.sas +121 -0
- package/macros/mp_assertscope.sas +147 -0
- package/macros/mp_base64copy.sas +117 -0
- package/macros/mp_binarycopy.sas +79 -0
- package/macros/mp_chop.sas +194 -0
- package/macros/mp_cleancsv.sas +78 -0
- package/macros/mp_cntlout.sas +85 -0
- package/macros/mp_copyfolder.sas +84 -0
- package/macros/mp_coretable.sas +73 -0
- package/macros/mp_createconstraints.sas +70 -0
- package/macros/mp_createwebservice.sas +32 -0
- package/macros/mp_csv2ds.sas +140 -0
- package/macros/mp_deleteconstraints.sas +52 -0
- package/macros/mp_deletefolder.sas +70 -0
- package/macros/mp_dictionary.sas +52 -0
- package/macros/mp_dirlist.sas +263 -0
- package/macros/mp_distinctfmtvalues.sas +50 -0
- package/macros/mp_dropmembers.sas +46 -0
- package/macros/mp_ds2cards.sas +291 -0
- package/macros/mp_ds2csv.sas +212 -0
- package/macros/mp_ds2ddl.sas +30 -0
- package/macros/mp_ds2fmtds.sas +105 -0
- package/macros/mp_ds2inserts.sas +180 -0
- package/macros/mp_ds2md.sas +103 -0
- package/macros/mp_ds2squeeze.sas +120 -0
- package/macros/mp_dsmeta.sas +110 -0
- package/macros/mp_filtercheck.sas +251 -0
- package/macros/mp_filtergenerate.sas +105 -0
- package/macros/mp_filterstore.sas +254 -0
- package/macros/mp_filtervalidate.sas +105 -0
- package/macros/mp_getcols.sas +67 -0
- package/macros/mp_getconstraints.sas +115 -0
- package/macros/mp_getdbml.sas +335 -0
- package/macros/mp_getddl.sas +400 -0
- package/macros/mp_getformats.sas +124 -0
- package/macros/mp_getmaxvarlengths.sas +130 -0
- package/macros/mp_getpk.sas +281 -0
- package/macros/mp_gsubfile.sas +58 -0
- package/macros/mp_guesspk.sas +332 -0
- package/macros/mp_hashdataset.sas +91 -0
- package/macros/mp_hashdirectory.sas +162 -0
- package/macros/mp_include.sas +106 -0
- package/macros/mp_init.sas +76 -0
- package/macros/mp_jsonout.sas +406 -0
- package/macros/mp_lib2cards.sas +78 -0
- package/macros/mp_lib2inserts.sas +77 -0
- package/macros/mp_loadformat.sas +303 -0
- package/macros/mp_lockanytable.sas +243 -0
- package/macros/mp_lockfilecheck.sas +103 -0
- package/macros/mp_makedata.sas +107 -0
- package/macros/mp_md5.sas +58 -0
- package/macros/mp_perflog.sas +43 -0
- package/macros/mp_prevobs.sas +88 -0
- package/macros/mp_recursivejoin.sas +90 -0
- package/macros/mp_replace.sas +151 -0
- package/macros/mp_reseterror.sas +27 -0
- package/macros/mp_resetoption.sas +39 -0
- package/macros/mp_retainedkey.sas +247 -0
- package/macros/mp_runddl.sas +49 -0
- package/macros/mp_searchcols.sas +103 -0
- package/macros/mp_searchdata.sas +131 -0
- package/macros/mp_setkeyvalue.sas +55 -0
- package/macros/mp_sortinplace.sas +122 -0
- package/macros/mp_stackdiffs.sas +592 -0
- package/macros/mp_storediffs.sas +230 -0
- package/macros/mp_stprequests.sas +74 -0
- package/macros/mp_streamfile.sas +212 -0
- package/macros/mp_testjob.sas +92 -0
- package/macros/mp_testservice.sas +39 -0
- package/macros/mp_testwritespeedlibrary.sas +59 -0
- package/macros/mp_tree.sas +71 -0
- package/macros/mp_unzip.sas +90 -0
- package/macros/mp_updatevarlength.sas +93 -0
- package/macros/mp_validatecol.sas +97 -0
- package/macros/mp_wait4file.sas +35 -0
- package/macros/mp_webin.sas +59 -0
- package/macros/mp_zip.sas +85 -0
- package/package.json +4 -1
- package/scripts/copySASjsCore.ts +36 -0
- package/utils/index.d.ts +1 -2
- package/utils/index.js +2 -3
- package/utils/index.js.map +1 -1
- package/utils/utils.d.ts +1 -0
- package/utils/utils.js +7 -1
- package/utils/utils.js.map +1 -1
- package/utils/getNodeModulePath.d.ts +0 -2
- package/utils/getNodeModulePath.js +0 -83
- package/utils/getNodeModulePath.js.map +0 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Checks & Stores an input filter table and returns the Filter Key
|
|
4
|
+
@details Used to generate a FILTER_RK from an input query dataset. This
|
|
5
|
+
process requires several permanent tables (names are configurable). The
|
|
6
|
+
benefit of storing query values at backend is to enable stored 'views' of
|
|
7
|
+
filtered tables at frontend (ie, when building [SAS-Powered Apps](
|
|
8
|
+
https://sasapps.io)). This macro is also used in [Data Controller for SAS](
|
|
9
|
+
https://datacontroller.io).
|
|
10
|
+
|
|
11
|
+
A more recent feature of this macro is the ability to support filter queries
|
|
12
|
+
on Format Catalogs. This is achieved by adding a `-FC` suffix to the `libds`
|
|
13
|
+
parameter - where the "ds" in this case is the catalog name.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@param [in] libds= The target dataset to be filtered (lib should be assigned).
|
|
17
|
+
If filtering a format catalog, add the following suffix: `-FC`.
|
|
18
|
+
@param [in] queryds= (WORK.FILTERQUERY) The temporary input query dataset to
|
|
19
|
+
be validated. Has the following format:
|
|
20
|
+
|GROUP_LOGIC:$3|SUBGROUP_LOGIC:$3|SUBGROUP_ID:8.|VARIABLE_NM:$32|OPERATOR_NM:$10|RAW_VALUE:$32767|
|
|
21
|
+
|---|---|---|---|---|---|
|
|
22
|
+
|AND|AND|1|SOME_BESTNUM|>|1|
|
|
23
|
+
|AND|AND|1|SOME_TIME|=|77333|
|
|
24
|
+
@param [in] filter_summary= (PERM.FILTER_SUMMARY) Permanent table containing
|
|
25
|
+
summary filter values. The definition is available by running
|
|
26
|
+
mp_coretable.sas as follows: `mp_coretable(FILTER_SUMMARY)`. Example
|
|
27
|
+
values:
|
|
28
|
+
|FILTER_RK:best.|FILTER_HASH:$32.|FILTER_TABLE:$41.|PROCESSED_DTTM:datetime19.|
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
|`1 `|`540E96F566D194AB58DD4C413C99C9DB `|`VIYA6014.MPE_TABLES `|`1956084246 `|
|
|
31
|
+
|`2 `|`87737DB9EEE2650F5C89956CEAD0A14F `|`VIYA6014.MPE_X_TEST `|`1956084452.1`|
|
|
32
|
+
|`3 `|`8048BD908DBBD83D013560734E90D394 `|`VIYA6014.MPE_TABLES `|`1956093620.6`|
|
|
33
|
+
@param [in] filter_detail= (PERM.FILTER_DETAIL) Permanent table containing
|
|
34
|
+
detailed (raw) filter values. The definition is available by running
|
|
35
|
+
mp_coretable.sas as follows: `mp_coretable(FILTER_DETAIL)`. Example
|
|
36
|
+
values:
|
|
37
|
+
|FILTER_HASH:$32.|FILTER_LINE:best.|GROUP_LOGIC:$3.|SUBGROUP_LOGIC:$3.|SUBGROUP_ID:best.|VARIABLE_NM:$32.|OPERATOR_NM:$12.|RAW_VALUE:$4000.|PROCESSED_DTTM:datetime19.|
|
|
38
|
+
|---|---|---|---|---|---|---|---|---|
|
|
39
|
+
|`540E96F566D194AB58DD4C413C99C9DB `|`1 `|`AND `|`AND `|`1 `|`LIBREF `|`CONTAINS `|`DC`|`1956084245.8 `|
|
|
40
|
+
|`540E96F566D194AB58DD4C413C99C9DB `|`2 `|`AND `|`OR `|`2 `|`DSN `|`= `|` MPE_LOCK_ANYTABLE `|`1956084245.8 `|
|
|
41
|
+
|`87737DB9EEE2650F5C89956CEAD0A14F `|`1 `|`AND `|`AND `|`1 `|`PRIMARY_KEY_FIELD `|`IN `|`(1,2,3) `|`1956084451.9 `|
|
|
42
|
+
@param [in] lock_table= (PERM.LOCK_TABLE) Permanent locking table. Used to
|
|
43
|
+
manage concurrent access. The definition is available by running
|
|
44
|
+
mp_coretable.sas as follows: `mp_coretable(LOCKTABLE)`.
|
|
45
|
+
@param [in] maxkeytable= (0) Optional permanent reference table used for
|
|
46
|
+
retained key tracking. Described in mp_retainedkey.sas.
|
|
47
|
+
@param [in] mdebug= set to 1 to enable DEBUG messages
|
|
48
|
+
@param [out] outresult= The result table with the FILTER_RK
|
|
49
|
+
@param [out] outquery= The original query, taken as extract after table load
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
<h4> SAS Macros </h4>
|
|
53
|
+
@li mddl_sas_cntlout.sas
|
|
54
|
+
@li mf_getuniquename.sas
|
|
55
|
+
@li mf_getvalue.sas
|
|
56
|
+
@li mf_islibds.sas
|
|
57
|
+
@li mf_nobs.sas
|
|
58
|
+
@li mp_abort.sas
|
|
59
|
+
@li mp_filtercheck.sas
|
|
60
|
+
@li mp_hashdataset.sas
|
|
61
|
+
@li mp_retainedkey.sas
|
|
62
|
+
|
|
63
|
+
<h4> Related Macros </h4>
|
|
64
|
+
@li mp_filtercheck.sas
|
|
65
|
+
@li mp_filtergenerate.sas
|
|
66
|
+
@li mp_filtervalidate.sas
|
|
67
|
+
@li mp_filterstore.test.sas
|
|
68
|
+
|
|
69
|
+
@version 9.2
|
|
70
|
+
@author [Allan Bowe](https://www.linkedin.com/in/allanbowe)
|
|
71
|
+
|
|
72
|
+
**/
|
|
73
|
+
|
|
74
|
+
%macro mp_filterstore(libds=,
|
|
75
|
+
queryds=work.filterquery,
|
|
76
|
+
filter_summary=PERM.FILTER_SUMMARY,
|
|
77
|
+
filter_detail=PERM.FILTER_DETAIL,
|
|
78
|
+
lock_table=PERM.LOCK_TABLE,
|
|
79
|
+
maxkeytable=PERM.MAXKEYTABLE,
|
|
80
|
+
outresult=work.result,
|
|
81
|
+
outquery=work.query,
|
|
82
|
+
mdebug=1
|
|
83
|
+
);
|
|
84
|
+
%put &sysmacroname entry vars:;
|
|
85
|
+
%put _local_;
|
|
86
|
+
|
|
87
|
+
%local ds0 ds1 ds2 ds3 ds4 filter_hash orig_libds;
|
|
88
|
+
%let libds=%upcase(&libds);
|
|
89
|
+
%let orig_libds=&libds;
|
|
90
|
+
|
|
91
|
+
%mp_abort(iftrue= (&syscc ne 0)
|
|
92
|
+
,mac=mp_filterstore
|
|
93
|
+
,msg=%str(syscc=&syscc on macro entry)
|
|
94
|
+
)
|
|
95
|
+
%mp_abort(iftrue= (%mf_islibds(&filter_summary)=0)
|
|
96
|
+
,mac=mp_filterstore
|
|
97
|
+
,msg=%str(Invalid filter_summary value: &filter_summary)
|
|
98
|
+
)
|
|
99
|
+
%mp_abort(iftrue= (%mf_islibds(&filter_detail)=0)
|
|
100
|
+
,mac=mp_filterstore
|
|
101
|
+
,msg=%str(Invalid filter_detail value: &filter_detail)
|
|
102
|
+
)
|
|
103
|
+
%mp_abort(iftrue= (%mf_islibds(&lock_table)=0)
|
|
104
|
+
,mac=mp_filterstore
|
|
105
|
+
,msg=%str(Invalid lock_table value: &lock_table)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* validate query
|
|
110
|
+
* use format catalog export, if a format
|
|
111
|
+
*/
|
|
112
|
+
%if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do;
|
|
113
|
+
%let libds=%scan(&libds,1,-); /* chop off -FC extension */
|
|
114
|
+
%let ds0=%mf_getuniquename(prefix=fmtds_);
|
|
115
|
+
%let libds=&ds0;
|
|
116
|
+
/*
|
|
117
|
+
There is no need to export the entire format catalog here - the validations
|
|
118
|
+
are done against the data model, not the data values. So we can simply
|
|
119
|
+
hardcode the structure based on the cntlout dataset.
|
|
120
|
+
*/
|
|
121
|
+
%mddl_sas_cntlout(libds=&ds0)
|
|
122
|
+
|
|
123
|
+
%end;
|
|
124
|
+
%mp_filtercheck(&queryds,targetds=&libds,abort=YES)
|
|
125
|
+
|
|
126
|
+
/* hash the result */
|
|
127
|
+
%let ds1=%mf_getuniquename(prefix=hashds);
|
|
128
|
+
%mp_hashdataset(&queryds,outds=&ds1,salt=&orig_libds)
|
|
129
|
+
%let filter_hash=%upcase(%mf_getvalue(&ds1,hashkey));
|
|
130
|
+
%if &mdebug=1 %then %do;
|
|
131
|
+
data _null_;
|
|
132
|
+
putlog "filter_hash=&filter_hash";
|
|
133
|
+
set &ds1;
|
|
134
|
+
putlog (_all_)(=);
|
|
135
|
+
run;
|
|
136
|
+
%end;
|
|
137
|
+
|
|
138
|
+
/* check if data already exists for this hash */
|
|
139
|
+
data &outresult;
|
|
140
|
+
set &filter_summary;
|
|
141
|
+
where filter_hash="&filter_hash";
|
|
142
|
+
run;
|
|
143
|
+
|
|
144
|
+
%mp_abort(iftrue= (&syscc ne 0)
|
|
145
|
+
,mac=mp_filterstore
|
|
146
|
+
,msg=%str(syscc=&syscc after hash check)
|
|
147
|
+
)
|
|
148
|
+
%mp_abort(iftrue= ("&filter_hash "=" ")
|
|
149
|
+
,mac=mp_filterstore
|
|
150
|
+
,msg=%str(problem with filter_hash generation)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
%if %mf_nobs(&outresult)=0 %then %do;
|
|
154
|
+
|
|
155
|
+
/* first update summary table */
|
|
156
|
+
%let ds3=%mf_getuniquename(prefix=filtersum);
|
|
157
|
+
data work.&ds3;
|
|
158
|
+
if 0 then set &filter_summary;
|
|
159
|
+
filter_table="&orig_libds";
|
|
160
|
+
filter_hash="&filter_hash";
|
|
161
|
+
PROCESSED_DTTM=%sysfunc(datetime());
|
|
162
|
+
output;
|
|
163
|
+
stop;
|
|
164
|
+
run;
|
|
165
|
+
|
|
166
|
+
%mp_lockanytable(LOCK,
|
|
167
|
+
lib=%scan(&filter_summary,1,.)
|
|
168
|
+
,ds=%scan(&filter_summary,2,.)
|
|
169
|
+
,ref=MP_FILTERSTORE summary update - &filter_hash
|
|
170
|
+
,ctl_ds=&lock_table
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
%let ds4=%mf_getuniquename(prefix=filtersumappend);
|
|
174
|
+
%mp_retainedkey(
|
|
175
|
+
base_lib=%scan(&filter_summary,1,.)
|
|
176
|
+
,base_dsn=%scan(&filter_summary,2,.)
|
|
177
|
+
,append_lib=work
|
|
178
|
+
,append_dsn=&ds3
|
|
179
|
+
,retained_key=filter_rk
|
|
180
|
+
,business_key=filter_hash
|
|
181
|
+
,maxkeytable=&maxkeytable
|
|
182
|
+
,locktable=&lock_table
|
|
183
|
+
,outds=work.&ds4
|
|
184
|
+
)
|
|
185
|
+
proc append base=&filter_summary data=&ds4;
|
|
186
|
+
run;
|
|
187
|
+
|
|
188
|
+
%mp_lockanytable(UNLOCK,
|
|
189
|
+
lib=%scan(&filter_summary,1,.)
|
|
190
|
+
,ds=%scan(&filter_summary,2,.)
|
|
191
|
+
,ref=MP_FILTERSTORE summary update - &filter_hash
|
|
192
|
+
,ctl_ds=&lock_table
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
%if &syscc ne 0 %then %do;
|
|
196
|
+
data _null_;
|
|
197
|
+
set &ds4;
|
|
198
|
+
putlog (_all_)(=);
|
|
199
|
+
run;
|
|
200
|
+
%goto err;
|
|
201
|
+
%end;
|
|
202
|
+
|
|
203
|
+
data &outresult;
|
|
204
|
+
set &filter_summary;
|
|
205
|
+
where filter_hash="&filter_hash";
|
|
206
|
+
run;
|
|
207
|
+
|
|
208
|
+
/* Next, update detail table */
|
|
209
|
+
%let ds2=%mf_getuniquename(prefix=filterdetail);
|
|
210
|
+
data &ds2;
|
|
211
|
+
if 0 then set &filter_detail;
|
|
212
|
+
set &queryds;
|
|
213
|
+
format filter_hash $hex32. filter_line 8.;
|
|
214
|
+
filter_hash="&filter_hash";
|
|
215
|
+
filter_line=_n_;
|
|
216
|
+
PROCESSED_DTTM=%sysfunc(datetime());
|
|
217
|
+
run;
|
|
218
|
+
%mp_lockanytable(LOCK,
|
|
219
|
+
lib=%scan(&filter_detail,1,.)
|
|
220
|
+
,ds=%scan(&filter_detail,2,.)
|
|
221
|
+
,ref=MP_FILTERSTORE update - &filter_hash
|
|
222
|
+
,ctl_ds=&lock_table
|
|
223
|
+
)
|
|
224
|
+
proc append base=&filter_detail data=&ds2;
|
|
225
|
+
run;
|
|
226
|
+
|
|
227
|
+
%mp_lockanytable(UNLOCK,
|
|
228
|
+
lib=%scan(&filter_detail,1,.)
|
|
229
|
+
,ds=%scan(&filter_detail,2,.)
|
|
230
|
+
,ref=MP_FILTERSTORE detail update &filter_hash
|
|
231
|
+
,ctl_ds=&lock_table
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
%if &syscc ne 0 %then %do;
|
|
235
|
+
data _null_;
|
|
236
|
+
set &ds2;
|
|
237
|
+
putlog (_all_)(=);
|
|
238
|
+
run;
|
|
239
|
+
%goto err;
|
|
240
|
+
%end;
|
|
241
|
+
|
|
242
|
+
%end;
|
|
243
|
+
|
|
244
|
+
proc sort data=&filter_detail(where=(filter_hash="&filter_hash")) out=&outquery;
|
|
245
|
+
by filter_line;
|
|
246
|
+
run;
|
|
247
|
+
|
|
248
|
+
%err:
|
|
249
|
+
%mp_abort(iftrue= (&syscc ne 0)
|
|
250
|
+
,mac=mp_filterstore
|
|
251
|
+
,msg=%str(syscc=&syscc on macro exit)
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
%mend mp_filterstore;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Checks a generated filter query for validity
|
|
4
|
+
@details Runs a generated filter in proc sql with the validate option.
|
|
5
|
+
Used in mp_filtercheck.sas in an fcmp container.
|
|
6
|
+
|
|
7
|
+
Built to support dynamic filtering in
|
|
8
|
+
[Data Controller for SAS®](https://datacontroller.io).
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
|
|
12
|
+
data work.filtertable;
|
|
13
|
+
infile datalines4 dsd;
|
|
14
|
+
input GROUP_LOGIC:$3. SUBGROUP_LOGIC:$3. SUBGROUP_ID:8. VARIABLE_NM:$32.
|
|
15
|
+
OPERATOR_NM:$10. RAW_VALUE:$4000.;
|
|
16
|
+
datalines4;
|
|
17
|
+
AND,AND,1,AGE,=,12
|
|
18
|
+
AND,AND,1,SEX,<=,"'M'"
|
|
19
|
+
AND,OR,2,Name,NOT IN,"('Jane','Alfred')"
|
|
20
|
+
AND,OR,2,Weight,>=,7
|
|
21
|
+
;;;;
|
|
22
|
+
run;
|
|
23
|
+
|
|
24
|
+
%mp_filtergenerate(work.filtertable,outref=myfilter)
|
|
25
|
+
|
|
26
|
+
%mp_filtervalidate(myfilter,sashelp.class)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@returns The SYSCC value will be 1008 if there are validation issues.
|
|
30
|
+
|
|
31
|
+
@param [in] inref The input fileref to validate (generated by
|
|
32
|
+
mp_filtergenerate.sas)
|
|
33
|
+
@param [in] targetds The target dataset against which to verify the query
|
|
34
|
+
@param [out] abort= (YES) If YES will call mp_abort.sas on any exceptions
|
|
35
|
+
@param [out] outds= (work.mp_filtervalidate) Output dataset containing the
|
|
36
|
+
err / warning message, if one exists. If this table contains any rows,
|
|
37
|
+
there are problems!
|
|
38
|
+
|
|
39
|
+
<h4> SAS Macros </h4>
|
|
40
|
+
@li mf_getuniquefileref.sas
|
|
41
|
+
@li mf_nobs.sas
|
|
42
|
+
@li mp_abort.sas
|
|
43
|
+
|
|
44
|
+
<h4> Related Macros </h4>
|
|
45
|
+
@li mp_filtercheck.sas
|
|
46
|
+
@li mp_filtergenerate.sas
|
|
47
|
+
|
|
48
|
+
@version 9.3
|
|
49
|
+
@author Allan Bowe
|
|
50
|
+
|
|
51
|
+
**/
|
|
52
|
+
|
|
53
|
+
%macro mp_filtervalidate(inref,targetds,abort=YES,outds=work.mp_filtervalidate);
|
|
54
|
+
|
|
55
|
+
%mp_abort(iftrue= (&syscc ne 0 or &syserr ne 0)
|
|
56
|
+
,mac=&sysmacroname
|
|
57
|
+
,msg=%str(syscc=&syscc / syserr=&syserr - on macro entry)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
%local fref1;
|
|
61
|
+
%let fref1=%mf_getuniquefileref();
|
|
62
|
+
|
|
63
|
+
data _null_;
|
|
64
|
+
file &fref1;
|
|
65
|
+
infile &inref end=eof;
|
|
66
|
+
if _n_=1 then do;
|
|
67
|
+
put "proc sql;";
|
|
68
|
+
put "validate select * from &targetds";
|
|
69
|
+
put "where " ;
|
|
70
|
+
end;
|
|
71
|
+
input;
|
|
72
|
+
put _infile_;
|
|
73
|
+
putlog _infile_;
|
|
74
|
+
if eof then put ";quit;";
|
|
75
|
+
run;
|
|
76
|
+
|
|
77
|
+
%inc &fref1;
|
|
78
|
+
|
|
79
|
+
data &outds;
|
|
80
|
+
if &sqlrc or &syscc or &syserr then do;
|
|
81
|
+
REASON_CD='VALIDATION_ERR'!!'OR: '!!
|
|
82
|
+
coalescec(symget('SYSERRORTEXT'),symget('SYSWARNINGTEXT'));
|
|
83
|
+
output;
|
|
84
|
+
end;
|
|
85
|
+
else stop;
|
|
86
|
+
run;
|
|
87
|
+
|
|
88
|
+
filename &fref1 clear;
|
|
89
|
+
|
|
90
|
+
%if %mf_nobs(&outds)>0 %then %do;
|
|
91
|
+
%if &abort=YES %then %do;
|
|
92
|
+
data _null_;
|
|
93
|
+
set &outds;
|
|
94
|
+
call symputx('REASON_CD',reason_cd,'l');
|
|
95
|
+
stop;
|
|
96
|
+
run;
|
|
97
|
+
%mp_abort(
|
|
98
|
+
mac=&sysmacroname,
|
|
99
|
+
msg=%str(Filter validation issues.)
|
|
100
|
+
)
|
|
101
|
+
%end;
|
|
102
|
+
%let syscc=1008;
|
|
103
|
+
%end;
|
|
104
|
+
|
|
105
|
+
%mend mp_filtervalidate;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Creates a dataset with column metadata.
|
|
4
|
+
@details This macro takes the `proc contents` output and "tidies it up" in the
|
|
5
|
+
following ways:
|
|
6
|
+
|
|
7
|
+
@li Blank labels are filled in with column names
|
|
8
|
+
@li Formats are reconstructed with default values
|
|
9
|
+
@li Types such as DATE / TIME / DATETIME are inferred from the formats
|
|
10
|
+
|
|
11
|
+
Example usage:
|
|
12
|
+
|
|
13
|
+
%mp_getcols(sashelp.airline,outds=work.myds)
|
|
14
|
+
|
|
15
|
+
@param ds The dataset from which to obtain column metadata
|
|
16
|
+
@param outds= (work.cols) The output dataset to create. Sample data:
|
|
17
|
+
|NAME:$32.|LENGTH:best.|VARNUM:best.|LABEL:$256.|FMTNAME:$32.|FORMAT:$49.|TYPE:$1.|DDTYPE:$9.|
|
|
18
|
+
|---|---|---|---|---|---|---|---|
|
|
19
|
+
|`AIR `|`8 `|`2 `|`international airline travel (thousands) `|` `|`8. `|`N `|`NUMERIC `|
|
|
20
|
+
|`DATE `|`8 `|`1 `|`DATE `|`MONYY `|`MONYY. `|`N `|`DATE `|
|
|
21
|
+
|`REGION `|`3 `|`3 `|`REGION `|` `|`$3. `|`C `|`CHARACTER `|
|
|
22
|
+
|
|
23
|
+
<h4> Related Macros </h4>
|
|
24
|
+
@li mf_getvarlist.sas
|
|
25
|
+
@li mm_getcols.sas
|
|
26
|
+
|
|
27
|
+
@version 9.2
|
|
28
|
+
@author Allan Bowe
|
|
29
|
+
|
|
30
|
+
**/
|
|
31
|
+
|
|
32
|
+
%macro mp_getcols(ds, outds=work.cols);
|
|
33
|
+
%local dropds;
|
|
34
|
+
proc contents noprint data=&ds
|
|
35
|
+
out=_data_ (keep=name type length label varnum format:);
|
|
36
|
+
run;
|
|
37
|
+
%let dropds=&syslast;
|
|
38
|
+
data &outds(keep=name type length varnum format label ddtype fmtname);
|
|
39
|
+
set &dropds(rename=(format=fmtname type=type2));
|
|
40
|
+
name=upcase(name);
|
|
41
|
+
if type2=2 then do;
|
|
42
|
+
length format $49.;
|
|
43
|
+
if fmtname='' then format=cats('$',length,'.');
|
|
44
|
+
else if formatl=0 then format=cats(fmtname,'.');
|
|
45
|
+
else format=cats(fmtname,formatl,'.');
|
|
46
|
+
type='C';
|
|
47
|
+
ddtype='CHARACTER';
|
|
48
|
+
end;
|
|
49
|
+
else do;
|
|
50
|
+
if fmtname='' then format=cats(length,'.');
|
|
51
|
+
else if formatl=0 then format=cats(fmtname,'.');
|
|
52
|
+
else if formatd=0 then format=cats(fmtname,formatl,'.');
|
|
53
|
+
else format=cats(fmtname,formatl,'.',formatd);
|
|
54
|
+
type='N';
|
|
55
|
+
if format=:'DATETIME' or format=:'E8601DT' then ddtype='DATETIME';
|
|
56
|
+
else if format=:'DATE' or format=:'DDMMYY' or format=:'MMDDYY'
|
|
57
|
+
or format=:'YYMMDD' or format=:'E8601DA' or format=:'B8601DA'
|
|
58
|
+
or format=:'MONYY'
|
|
59
|
+
then ddtype='DATE';
|
|
60
|
+
else if format=:'TIME' then ddtype='TIME';
|
|
61
|
+
else ddtype='NUMERIC';
|
|
62
|
+
end;
|
|
63
|
+
if label='' then label=name;
|
|
64
|
+
run;
|
|
65
|
+
proc sql;
|
|
66
|
+
drop table &dropds;
|
|
67
|
+
%mend mp_getcols;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_getconstraints.sas
|
|
3
|
+
@brief Get constraint details at column level
|
|
4
|
+
@details Useful for capturing constraints before they are dropped / reapplied
|
|
5
|
+
during an update.
|
|
6
|
+
|
|
7
|
+
proc sql;
|
|
8
|
+
create table work.example(
|
|
9
|
+
TX_FROM float format=datetime19.,
|
|
10
|
+
DD_TYPE char(16),
|
|
11
|
+
DD_SOURCE char(2048),
|
|
12
|
+
DD_SHORTDESC char(256),
|
|
13
|
+
constraint pk primary key(tx_from, dd_type,dd_source),
|
|
14
|
+
constraint unq unique(tx_from, dd_type),
|
|
15
|
+
constraint nnn not null(DD_SHORTDESC)
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
%mp_getconstraints(lib=work,ds=example,outds=work.constraints)
|
|
19
|
+
|
|
20
|
+
@param [in] lib= (WORK) The target library
|
|
21
|
+
@param [in] ds= The target dataset. Leave blank (default) for all datasets.
|
|
22
|
+
@param [in] mdebug= (0) Set to 1 to preserve temp tables, print var values etc
|
|
23
|
+
@param [out] outds= (mp_getconstraints) the output dataset
|
|
24
|
+
|
|
25
|
+
<h4> SAS Macros </h4>
|
|
26
|
+
@li mf_getuniquename.sas
|
|
27
|
+
@li mp_dropmembers.sas
|
|
28
|
+
|
|
29
|
+
@version 9.2
|
|
30
|
+
@author Allan Bowe
|
|
31
|
+
|
|
32
|
+
**/
|
|
33
|
+
|
|
34
|
+
%macro mp_getconstraints(lib=WORK
|
|
35
|
+
,ds=
|
|
36
|
+
,outds=mp_getconstraints
|
|
37
|
+
,mdebug=0
|
|
38
|
+
)/*/STORE SOURCE*/;
|
|
39
|
+
|
|
40
|
+
%let lib=%upcase(&lib);
|
|
41
|
+
%let ds=%upcase(&ds);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Cater for environments where sashelp.vcncolu is not available
|
|
45
|
+
*/
|
|
46
|
+
%if %sysfunc(exist(sashelp.vcncolu,view))=0 %then %do;
|
|
47
|
+
proc sql;
|
|
48
|
+
create table &outds(
|
|
49
|
+
libref char(8)
|
|
50
|
+
,TABLE_NAME char(32)
|
|
51
|
+
,constraint_type char(8) label='Constraint Type'
|
|
52
|
+
,constraint_name char(32) label='Constraint Name'
|
|
53
|
+
,column_name char(32) label='Column'
|
|
54
|
+
,constraint_order num
|
|
55
|
+
);
|
|
56
|
+
%return;
|
|
57
|
+
%end;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Neither dictionary tables nor sashelp provides a constraint order column,
|
|
61
|
+
* however they DO arrive in the correct order. So, create the col.
|
|
62
|
+
**/
|
|
63
|
+
%local vw;
|
|
64
|
+
%let vw=%mf_getuniquename(prefix=mp_getconstraints_vw_);
|
|
65
|
+
data &vw /view=&vw;
|
|
66
|
+
set sashelp.vcncolu;
|
|
67
|
+
where table_catalog="&lib";
|
|
68
|
+
|
|
69
|
+
/* use retain approach to reset the constraint order with each constraint */
|
|
70
|
+
length tmp $1000;
|
|
71
|
+
retain tmp;
|
|
72
|
+
drop tmp;
|
|
73
|
+
if tmp ne catx('|',table_catalog,table_name,constraint_name) then do;
|
|
74
|
+
constraint_order=1;
|
|
75
|
+
end;
|
|
76
|
+
else constraint_order+1;
|
|
77
|
+
tmp=catx('|',table_catalog, table_name,constraint_name);
|
|
78
|
+
run;
|
|
79
|
+
|
|
80
|
+
/* must use SQL as proc datasets does not support length changes */
|
|
81
|
+
proc sql noprint;
|
|
82
|
+
create table &outds as
|
|
83
|
+
select upcase(a.TABLE_CATALOG) as libref
|
|
84
|
+
,upcase(a.TABLE_NAME) as TABLE_NAME
|
|
85
|
+
,a.constraint_type
|
|
86
|
+
,a.constraint_name
|
|
87
|
+
,b.column_name
|
|
88
|
+
,b.constraint_order
|
|
89
|
+
from dictionary.TABLE_CONSTRAINTS a
|
|
90
|
+
left join &vw b
|
|
91
|
+
on upcase(a.TABLE_CATALOG)=upcase(b.TABLE_CATALOG)
|
|
92
|
+
and upcase(a.TABLE_NAME)=upcase(b.TABLE_NAME)
|
|
93
|
+
and a.constraint_name=b.constraint_name
|
|
94
|
+
/**
|
|
95
|
+
* We cannot apply this clause to the underlying dictionary table. See:
|
|
96
|
+
* https://communities.sas.com/t5/SAS-Programming/Unexpected-Where-Clause-behaviour-in-dictionary-TABLE/m-p/771554#M244867
|
|
97
|
+
* cannot use`where calculated libref="&lib"` either as it will STILL execute
|
|
98
|
+
* all the underlying constraint queries, causing exception errors in some
|
|
99
|
+
* cases: https://github.com/sasjs/core/issues/283
|
|
100
|
+
*/
|
|
101
|
+
where a.TABLE_CATALOG="&lib"
|
|
102
|
+
%if "&ds" ne "" %then %do;
|
|
103
|
+
and upcase(a.TABLE_NAME)="&ds"
|
|
104
|
+
and upcase(b.TABLE_NAME)="&ds"
|
|
105
|
+
%end;
|
|
106
|
+
order by libref, table_name, constraint_name, constraint_order
|
|
107
|
+
;
|
|
108
|
+
|
|
109
|
+
/* tidy up */
|
|
110
|
+
%mp_dropmembers(
|
|
111
|
+
&vw,
|
|
112
|
+
iftrue=(&mdebug=0)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
%mend mp_getconstraints;
|