@sasjs/utils 2.48.2 → 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/generateCompileProgram.d.ts +1 -0
- package/fs/generateCompileProgram.js +154 -0
- package/fs/generateCompileProgram.js.map +1 -0
- package/fs/hash.d.ts +22 -0
- package/fs/hash.js +225 -0
- package/fs/hash.js.map +1 -0
- package/fs/index.d.ts +3 -0
- package/fs/index.js +13 -0
- package/fs/index.js.map +1 -0
- package/fs/internal/helper.d.ts +4 -0
- package/fs/internal/helper.js +125 -0
- package/fs/internal/helper.js.map +1 -0
- package/fs/sync.d.ts +6 -0
- package/fs/sync.js +208 -0
- package/fs/sync.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.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 +5 -2
- package/scripts/copySASjsCore.ts +36 -0
- package/types/hash.d.ts +9 -0
- package/types/hash.js +3 -0
- package/types/hash.js.map +1 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +1 -0
- package/types/index.js.map +1 -1
- package/utils/index.d.ts +1 -1
- package/utils/index.js +2 -1
- 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
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Create a CARDS file from a SAS dataset.
|
|
4
|
+
@details Uses dataset attributes to convert all data into datalines.
|
|
5
|
+
Running the generated file will rebuild the original dataset. Includes
|
|
6
|
+
support for large decimals, binary data, PROCESSED_DTTM columns, and
|
|
7
|
+
alternative encoding. If the input dataset is empty, the cards file will
|
|
8
|
+
still be created.
|
|
9
|
+
|
|
10
|
+
Additional support to generate a random sample and max rows.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
|
|
14
|
+
%mp_ds2cards(sashelp.class
|
|
15
|
+
, tgt_ds=work.class
|
|
16
|
+
, cards_file= "C:\temp\class.sas"
|
|
17
|
+
, showlog=NO
|
|
18
|
+
, maxobs=5
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
TODO:
|
|
22
|
+
- labelling the dataset
|
|
23
|
+
- explicity setting a unix LF
|
|
24
|
+
- constraints / indexes etc
|
|
25
|
+
|
|
26
|
+
@param [in] base_ds Should be two level - eg work.blah. This is the table
|
|
27
|
+
that is converted to a cards file.
|
|
28
|
+
@param [in] tgt_ds= Table that the generated cards file would create.
|
|
29
|
+
Optional - if omitted, will be same as BASE_DS.
|
|
30
|
+
@param [out] cards_file= ("%sysfunc(pathname(work))/cardgen.sas") Location in
|
|
31
|
+
which to write the (.sas) cards file
|
|
32
|
+
@param [in] maxobs= (max) To limit output to the first <code>maxobs</code>
|
|
33
|
+
observations, enter an integer here.
|
|
34
|
+
@param [in] random_sample= (NO) Set to YES to generate a random sample of
|
|
35
|
+
data. Can be quite slow.
|
|
36
|
+
@param [in] showlog= (YES) Whether to show generated cards file in the SAS
|
|
37
|
+
log. Valid values:
|
|
38
|
+
@li YES
|
|
39
|
+
@li NO
|
|
40
|
+
@param [in] outencoding= Provide encoding value for file statement (eg utf-8)
|
|
41
|
+
@param [in] append= (NO) If NO then will rebuild the cards file if it already
|
|
42
|
+
exists, otherwise will append to it. Used by the mp_lib2cards.sas macro.
|
|
43
|
+
|
|
44
|
+
<h4> Related Macros </h4>
|
|
45
|
+
@li mp_lib2cards.sas
|
|
46
|
+
@li mp_ds2inserts.sas
|
|
47
|
+
@li mp_mdtablewrite.sas
|
|
48
|
+
|
|
49
|
+
@version 9.2
|
|
50
|
+
@author Allan Bowe
|
|
51
|
+
@cond
|
|
52
|
+
**/
|
|
53
|
+
|
|
54
|
+
%macro mp_ds2cards(base_ds, tgt_ds=
|
|
55
|
+
,cards_file="%sysfunc(pathname(work))/cardgen.sas"
|
|
56
|
+
,maxobs=max
|
|
57
|
+
,random_sample=NO
|
|
58
|
+
,showlog=YES
|
|
59
|
+
,outencoding=
|
|
60
|
+
,append=NO
|
|
61
|
+
)/*/STORE SOURCE*/;
|
|
62
|
+
%local i setds nvars;
|
|
63
|
+
|
|
64
|
+
%if not %sysfunc(exist(&base_ds)) %then %do;
|
|
65
|
+
%put %str(WARN)ING: &base_ds does not exist;
|
|
66
|
+
%return;
|
|
67
|
+
%end;
|
|
68
|
+
|
|
69
|
+
%if %index(&base_ds,.)=0 %then %let base_ds=WORK.&base_ds;
|
|
70
|
+
%if (&tgt_ds = ) %then %let tgt_ds=&base_ds;
|
|
71
|
+
%if %index(&tgt_ds,.)=0 %then %let tgt_ds=WORK.%scan(&base_ds,2,.);
|
|
72
|
+
%if ("&outencoding" ne "") %then %let outencoding=encoding="&outencoding";
|
|
73
|
+
%if ("&append" = "" or "&append" = "NO") %then %let append=;
|
|
74
|
+
%else %let append=mod;
|
|
75
|
+
|
|
76
|
+
/* get varcount */
|
|
77
|
+
%let nvars=0;
|
|
78
|
+
proc sql noprint;
|
|
79
|
+
select count(*) into: nvars from dictionary.columns
|
|
80
|
+
where upcase(libname)="%scan(%upcase(&base_ds),1)"
|
|
81
|
+
and upcase(memname)="%scan(%upcase(&base_ds),2)";
|
|
82
|
+
%if &nvars=0 %then %do;
|
|
83
|
+
%put %str(WARN)ING: Dataset &base_ds has no variables, will not be converted.;
|
|
84
|
+
%return;
|
|
85
|
+
%end;
|
|
86
|
+
|
|
87
|
+
/* get indexes */
|
|
88
|
+
proc sort
|
|
89
|
+
data=sashelp.vindex(
|
|
90
|
+
where=(upcase(libname)="%scan(%upcase(&base_ds),1)"
|
|
91
|
+
and upcase(memname)="%scan(%upcase(&base_ds),2)")
|
|
92
|
+
)
|
|
93
|
+
out=_data_;
|
|
94
|
+
by indxname indxpos;
|
|
95
|
+
run;
|
|
96
|
+
|
|
97
|
+
%local indexes;
|
|
98
|
+
data _null_;
|
|
99
|
+
set &syslast end=last;
|
|
100
|
+
if _n_=1 then call symputx('indexes','(index=(','l');
|
|
101
|
+
by indxname indxpos;
|
|
102
|
+
length vars $32767 nom uni $8;
|
|
103
|
+
retain vars;
|
|
104
|
+
if first.indxname then do;
|
|
105
|
+
idxcnt+1;
|
|
106
|
+
nom='';
|
|
107
|
+
uni='';
|
|
108
|
+
vars=name;
|
|
109
|
+
end;
|
|
110
|
+
else vars=catx(' ',vars,name);
|
|
111
|
+
if last.indxname then do;
|
|
112
|
+
if nomiss='yes' then nom='/nomiss';
|
|
113
|
+
if unique='yes' then uni='/unique';
|
|
114
|
+
call symputx('indexes'
|
|
115
|
+
,catx(' ',symget('indexes'),indxname,'=(',vars,')',nom,uni)
|
|
116
|
+
,'l');
|
|
117
|
+
end;
|
|
118
|
+
if last then call symputx('indexes',cats(symget('indexes'),'))'),'l');
|
|
119
|
+
run;
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
data;run;
|
|
123
|
+
%let setds=&syslast;
|
|
124
|
+
proc sql
|
|
125
|
+
%if %datatyp(&maxobs)=NUMERIC %then %do;
|
|
126
|
+
outobs=&maxobs;
|
|
127
|
+
%end;
|
|
128
|
+
;
|
|
129
|
+
create table &setds as select * from &base_ds
|
|
130
|
+
%if &random_sample=YES %then %do;
|
|
131
|
+
order by ranuni(42)
|
|
132
|
+
%end;
|
|
133
|
+
;
|
|
134
|
+
reset outobs=max;
|
|
135
|
+
create table datalines1 as
|
|
136
|
+
select name,type,length,varnum,format,label from dictionary.columns
|
|
137
|
+
where upcase(libname)="%upcase(%scan(&base_ds,1))"
|
|
138
|
+
and upcase(memname)="%upcase(%scan(&base_ds,2))";
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
Due to long decimals cannot use best. format
|
|
142
|
+
So - use bestd. format and then use character functions to strip trailing
|
|
143
|
+
zeros, if NOT an integer or missing!! Cannot use int() as it upsets
|
|
144
|
+
note2err when there are missings.
|
|
145
|
+
resolved code = ifc( mod(coalesce(VARIABLE,0),1)=0
|
|
146
|
+
,put(VARIABLE,best32.)
|
|
147
|
+
,substrn(put(VARIABLE,bestd32.),1
|
|
148
|
+
,findc(put(VARIABLE,bestd32.),'0','TBK')));
|
|
149
|
+
**/
|
|
150
|
+
|
|
151
|
+
data datalines_2;
|
|
152
|
+
format dataline $32000.;
|
|
153
|
+
set datalines1 (where=(upcase(name) not in
|
|
154
|
+
('PROCESSED_DTTM','VALID_FROM_DTTM','VALID_TO_DTTM')));
|
|
155
|
+
if type='num' then dataline=
|
|
156
|
+
cats('ifc(mod(coalesce(',name,',0),1)=0
|
|
157
|
+
,put(',name,',best32.-l)
|
|
158
|
+
,substrn(put(',name,',bestd32.-l),1
|
|
159
|
+
,findc(put(',name,',bestd32.-l),"0","TBK")))');
|
|
160
|
+
/**
|
|
161
|
+
* binary data must be converted, to store in text format. It is identified
|
|
162
|
+
* by the presence of the $HEX keyword in the format.
|
|
163
|
+
*/
|
|
164
|
+
else if upcase(format)=:'$HEX' then
|
|
165
|
+
dataline=cats('put(trim(',name,'),',format,')');
|
|
166
|
+
/**
|
|
167
|
+
* There is no easy way to store line breaks in a cards file.
|
|
168
|
+
* To discuss this, use: https://github.com/sasjs/core/issues/80
|
|
169
|
+
* Removing all nonprintables with kw (keep writeable)
|
|
170
|
+
*/
|
|
171
|
+
else dataline=cats('compress(',name,', ,"kw")');
|
|
172
|
+
run;
|
|
173
|
+
|
|
174
|
+
proc sql noprint;
|
|
175
|
+
select dataline into: datalines separated by ',' from datalines_2;
|
|
176
|
+
|
|
177
|
+
%local
|
|
178
|
+
process_dttm_flg
|
|
179
|
+
valid_from_dttm_flg
|
|
180
|
+
valid_to_dttm_flg
|
|
181
|
+
;
|
|
182
|
+
%let process_dttm_flg = N;
|
|
183
|
+
%let valid_from_dttm_flg = N;
|
|
184
|
+
%let valid_to_dttm_flg = N;
|
|
185
|
+
data _null_;
|
|
186
|
+
set datalines1 ;
|
|
187
|
+
/* build attrib statement */
|
|
188
|
+
if type='char' then type2='$';
|
|
189
|
+
if strip(format) ne '' then format2=cats('format=',format);
|
|
190
|
+
if strip(label) ne '' then label2=cats('label=',quote(trim(label)));
|
|
191
|
+
str1=catx(' ',(put(name,$33.)||'length=')
|
|
192
|
+
,put(cats(type2,length),$7.)||format2,label2);
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/* Build input statement */
|
|
196
|
+
if upcase(format)=:'$HEX' then type3=':'!!format;
|
|
197
|
+
else if type='char' then type3=':$char.';
|
|
198
|
+
str2=put(name,$33.)||type3;
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
if(upcase(name) = "PROCESSED_DTTM") then
|
|
202
|
+
call symputx("process_dttm_flg", "Y", "L");
|
|
203
|
+
if(upcase(name) = "VALID_FROM_DTTM") then
|
|
204
|
+
call symputx("valid_from_dttm_flg", "Y", "L");
|
|
205
|
+
if(upcase(name) = "VALID_TO_DTTM") then
|
|
206
|
+
call symputx("valid_to_dttm_flg", "Y", "L");
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
call symputx(cats("attrib_stmt_", put(_N_, 8.)), str1, "L");
|
|
210
|
+
call symputx(cats("input_stmt_", put(_N_, 8.))
|
|
211
|
+
, ifc(upcase(name) not in
|
|
212
|
+
('PROCESSED_DTTM','VALID_FROM_DTTM','VALID_TO_DTTM'), str2, ""), "L");
|
|
213
|
+
run;
|
|
214
|
+
|
|
215
|
+
data _null_;
|
|
216
|
+
file &cards_file. &outencoding lrecl=32767 termstr=nl &append;
|
|
217
|
+
length __attrib $32767;
|
|
218
|
+
if _n_=1 then do;
|
|
219
|
+
put '/**';
|
|
220
|
+
put ' @file';
|
|
221
|
+
put " @brief Datalines for %upcase(%scan(&base_ds,2)) dataset";
|
|
222
|
+
put " @details Generated by %nrstr(%%)mp_ds2cards()";
|
|
223
|
+
put " Source: https://github.com/sasjs/core";
|
|
224
|
+
put ' @cond ';
|
|
225
|
+
put '**/';
|
|
226
|
+
put "data &tgt_ds &indexes;";
|
|
227
|
+
put "attrib ";
|
|
228
|
+
%do i = 1 %to &nvars;
|
|
229
|
+
__attrib=symget("attrib_stmt_&i");
|
|
230
|
+
put __attrib;
|
|
231
|
+
%end;
|
|
232
|
+
put ";";
|
|
233
|
+
|
|
234
|
+
%if &process_dttm_flg. eq Y %then %do;
|
|
235
|
+
put 'retain PROCESSED_DTTM %sysfunc(datetime());';
|
|
236
|
+
%end;
|
|
237
|
+
%if &valid_from_dttm_flg. eq Y %then %do;
|
|
238
|
+
put 'retain VALID_FROM_DTTM &low_date;';
|
|
239
|
+
%end;
|
|
240
|
+
%if &valid_to_dttm_flg. eq Y %then %do;
|
|
241
|
+
put 'retain VALID_TO_DTTM &high_date;';
|
|
242
|
+
%end;
|
|
243
|
+
if __nobs=0 then do;
|
|
244
|
+
put 'call missing(of _all_);/* avoid uninitialised notes */';
|
|
245
|
+
put 'stop;';
|
|
246
|
+
put 'run;';
|
|
247
|
+
end;
|
|
248
|
+
else do;
|
|
249
|
+
put "infile cards dsd;";
|
|
250
|
+
put "input ";
|
|
251
|
+
%do i = 1 %to &nvars.;
|
|
252
|
+
%if(%length(&&input_stmt_&i..)) %then
|
|
253
|
+
put " &&input_stmt_&i..";
|
|
254
|
+
;
|
|
255
|
+
%end;
|
|
256
|
+
put ";";
|
|
257
|
+
put 'missing a b c d e f g h i j k l m n o p q r s t u v w x y z _;';
|
|
258
|
+
put "datalines4;";
|
|
259
|
+
end;
|
|
260
|
+
end;
|
|
261
|
+
set &setds end=__lastobs nobs=__nobs;
|
|
262
|
+
/* remove all formats for write purposes - some have long underlying decimals */
|
|
263
|
+
format _numeric_ best30.29;
|
|
264
|
+
length __dataline $32767;
|
|
265
|
+
__dataline=catq('cqtmb',&datalines);
|
|
266
|
+
put __dataline;
|
|
267
|
+
if __lastobs then do;
|
|
268
|
+
put ';;;;';
|
|
269
|
+
put 'run;';
|
|
270
|
+
put '/** @endcond **/';
|
|
271
|
+
stop;
|
|
272
|
+
end;
|
|
273
|
+
run;
|
|
274
|
+
proc sql;
|
|
275
|
+
drop table &setds;
|
|
276
|
+
quit;
|
|
277
|
+
|
|
278
|
+
%if &showlog=YES %then %do;
|
|
279
|
+
data _null_;
|
|
280
|
+
infile &cards_file lrecl=32767;
|
|
281
|
+
input;
|
|
282
|
+
put _infile_;
|
|
283
|
+
run;
|
|
284
|
+
%end;
|
|
285
|
+
|
|
286
|
+
%put NOTE: CARDS FILE SAVED IN:;
|
|
287
|
+
%put NOTE-;%put NOTE-;
|
|
288
|
+
%put NOTE- %sysfunc(dequote(&cards_file.));
|
|
289
|
+
%put NOTE-;%put NOTE-;
|
|
290
|
+
%mend mp_ds2cards;
|
|
291
|
+
/** @endcond **/
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Export a dataset to a CSV file WITH leading blanks
|
|
4
|
+
@details Export a dataset to a file or fileref, retaining leading blanks.
|
|
5
|
+
|
|
6
|
+
When using SASJS headerformat, the input statement is provided in the first
|
|
7
|
+
row of the CSV.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
|
|
11
|
+
%mp_ds2csv(sashelp.class,outref="%sysfunc(pathname(work))/file.csv")
|
|
12
|
+
|
|
13
|
+
filename example temp;
|
|
14
|
+
%mp_ds2csv(sashelp.air,outref=example,headerformat=SASJS)
|
|
15
|
+
data; infile example; input;put _infile_; if _n_>5 then stop;run;
|
|
16
|
+
|
|
17
|
+
data _null_;
|
|
18
|
+
infile example;
|
|
19
|
+
input;
|
|
20
|
+
call symputx('stmnt',_infile_);
|
|
21
|
+
stop;
|
|
22
|
+
run;
|
|
23
|
+
data work.want;
|
|
24
|
+
infile example dsd firstobs=2;
|
|
25
|
+
input &stmnt;
|
|
26
|
+
run;
|
|
27
|
+
|
|
28
|
+
Why use mp_ds2csv over, say, proc export?
|
|
29
|
+
|
|
30
|
+
1. Ability to retain leading blanks (this is a major one)
|
|
31
|
+
2. Control the header format
|
|
32
|
+
3. Simple one-liner
|
|
33
|
+
|
|
34
|
+
@param [in] ds The dataset to be exported
|
|
35
|
+
@param [in] dlm= (COMMA) The delimeter to apply. For SASJS, will always be
|
|
36
|
+
COMMA. Supported values:
|
|
37
|
+
@li COMMA
|
|
38
|
+
@li SEMICOLON
|
|
39
|
+
@param [in] headerformat= (LABEL) The format to use for the header section.
|
|
40
|
+
Valid values:
|
|
41
|
+
@li LABEL - Use the variable label (or name, if blank)
|
|
42
|
+
@li NAME - Use the variable name
|
|
43
|
+
@li SASJS - Used to create sasjs-formatted input CSVs, eg for use in
|
|
44
|
+
mp_testservice.sas. This format will supply an input statement in the
|
|
45
|
+
first row, making ingestion by datastep a breeze. Special misisng values
|
|
46
|
+
will be prefixed with a period (eg `.A`) to enable ingestion on both SAS 9
|
|
47
|
+
and Viya. Dates / Datetimes etc are identified by the format type (lookup
|
|
48
|
+
with mcf_getfmttype.sas) and converted to human readable formats (not
|
|
49
|
+
numbers).
|
|
50
|
+
@param [out] outfile= The output filename - should be quoted.
|
|
51
|
+
@param [out] outref= (0) The output fileref (takes precedence if provided)
|
|
52
|
+
@param [in] outencoding= (0) The (quoted) output encoding to use, eg `"UTF-8"`
|
|
53
|
+
@param [in] termstr= (CRLF) The line seperator to use. For SASJS, will
|
|
54
|
+
always be CRLF. Valid values:
|
|
55
|
+
@li CRLF
|
|
56
|
+
@li LF
|
|
57
|
+
|
|
58
|
+
<h4> SAS Macros </h4>
|
|
59
|
+
@li mcf_getfmttype.sas
|
|
60
|
+
@li mf_getuniquename.sas
|
|
61
|
+
@li mf_getvarformat.sas
|
|
62
|
+
@li mf_getvarlist.sas
|
|
63
|
+
@li mf_getvartype.sas
|
|
64
|
+
|
|
65
|
+
@version 9.2
|
|
66
|
+
@author Allan Bowe (credit mjsq)
|
|
67
|
+
**/
|
|
68
|
+
|
|
69
|
+
%macro mp_ds2csv(ds
|
|
70
|
+
,dlm=COMMA
|
|
71
|
+
,outref=0
|
|
72
|
+
,outfile=
|
|
73
|
+
,outencoding=0
|
|
74
|
+
,headerformat=LABEL
|
|
75
|
+
,termstr=CRLF
|
|
76
|
+
)/*/STORE SOURCE*/;
|
|
77
|
+
|
|
78
|
+
%local outloc delim i varlist var vcnt vat dsv vcom vmiss fmttype vfmt;
|
|
79
|
+
|
|
80
|
+
%if not %sysfunc(exist(&ds)) %then %do;
|
|
81
|
+
%put %str(WARN)ING: &ds does not exist;
|
|
82
|
+
%return;
|
|
83
|
+
%end;
|
|
84
|
+
|
|
85
|
+
%if %index(&ds,.)=0 %then %let ds=WORK.&ds;
|
|
86
|
+
|
|
87
|
+
%if &outencoding=0 %then %let outencoding=;
|
|
88
|
+
%else %let outencoding=encoding=&outencoding;
|
|
89
|
+
|
|
90
|
+
%if &outref=0 %then %let outloc=&outfile;
|
|
91
|
+
%else %let outloc=&outref;
|
|
92
|
+
|
|
93
|
+
%if &headerformat=SASJS %then %do;
|
|
94
|
+
%let delim=",";
|
|
95
|
+
%let termstr=CRLF;
|
|
96
|
+
%mcf_getfmttype(wrap=YES)
|
|
97
|
+
%end;
|
|
98
|
+
%else %if &dlm=COMMA %then %let delim=",";
|
|
99
|
+
%else %let delim=";";
|
|
100
|
+
|
|
101
|
+
/* credit to mjsq - https://stackoverflow.com/a/55642267 */
|
|
102
|
+
|
|
103
|
+
/* first get headers */
|
|
104
|
+
data _null_;
|
|
105
|
+
file &outloc &outencoding lrecl=32767 termstr=&termstr;
|
|
106
|
+
length header $ 2000 varnm vfmt $32 dlm $1 fmttype $8;
|
|
107
|
+
call missing(of _all_);
|
|
108
|
+
dsid=open("&ds.","i");
|
|
109
|
+
num=attrn(dsid,"nvars");
|
|
110
|
+
dlm=&delim;
|
|
111
|
+
do i=1 to num;
|
|
112
|
+
varnm=upcase(varname(dsid,i));
|
|
113
|
+
if i=num then dlm='';
|
|
114
|
+
%if &headerformat=NAME %then %do;
|
|
115
|
+
header=cats(varnm,dlm);
|
|
116
|
+
%end;
|
|
117
|
+
%else %if &headerformat=LABEL %then %do;
|
|
118
|
+
header = cats(coalescec(varlabel(dsid,i),varnm),dlm);
|
|
119
|
+
%end;
|
|
120
|
+
%else %if &headerformat=SASJS %then %do;
|
|
121
|
+
if vartype(dsid,i)='C' then header=cats(varnm,':$char',varlen(dsid,i),'.');
|
|
122
|
+
else do;
|
|
123
|
+
vfmt=coalescec(varfmt(dsid,i),'0');
|
|
124
|
+
fmttype=mcf_getfmttype(vfmt);
|
|
125
|
+
if fmttype='DATE' then header=cats(varnm,':date9.');
|
|
126
|
+
else if fmttype='DATETIME' then header=cats(varnm,':E8601DT26.6');
|
|
127
|
+
else if fmttype='TIME' then header=cats(varnm,':TIME12.');
|
|
128
|
+
else header=cats(varnm,':best.');
|
|
129
|
+
end;
|
|
130
|
+
%end;
|
|
131
|
+
%else %do;
|
|
132
|
+
%put &sysmacroname: Invalid headerformat value (&headerformat);
|
|
133
|
+
%return;
|
|
134
|
+
%end;
|
|
135
|
+
put header @;
|
|
136
|
+
end;
|
|
137
|
+
rc=close(dsid);
|
|
138
|
+
run;
|
|
139
|
+
|
|
140
|
+
%let varlist=%mf_getvarlist(&ds);
|
|
141
|
+
%let vcnt=%sysfunc(countw(&varlist));
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The $quote modifier (without a width) will take the length from the variable
|
|
145
|
+
* and increase by two. However this will lead to truncation where the value
|
|
146
|
+
* contains double quotes (which are doubled up). To get around this, scan the
|
|
147
|
+
* data to see the max number of double quotes, so that the appropriate width
|
|
148
|
+
* can be applied in the subsequent step.
|
|
149
|
+
*/
|
|
150
|
+
data _null_;
|
|
151
|
+
set &ds end=last;
|
|
152
|
+
%do i=1 %to &vcnt;
|
|
153
|
+
%let var=%scan(&varlist,&i);
|
|
154
|
+
%if %mf_getvartype(&ds,&var)=C %then %do;
|
|
155
|
+
%let dsv1=%mf_getuniquename(prefix=csvcol1_);
|
|
156
|
+
%let dsv2=%mf_getuniquename(prefix=csvcol2_);
|
|
157
|
+
retain &dsv1 0;
|
|
158
|
+
&dsv2=length(&var)+countc(&var,'"');
|
|
159
|
+
if &dsv2>&dsv1 then &dsv1=&dsv2;
|
|
160
|
+
if last then call symputx(
|
|
161
|
+
"vlen&i"
|
|
162
|
+
/* should be no shorter than varlen, and no longer than 32767 */
|
|
163
|
+
,cats('$quote',min(&dsv1+2,32767),'.')
|
|
164
|
+
,'l'
|
|
165
|
+
);
|
|
166
|
+
%end;
|
|
167
|
+
%end;
|
|
168
|
+
|
|
169
|
+
%let vat=@;
|
|
170
|
+
%let vcom=&delim;
|
|
171
|
+
%let vmiss=%mf_getuniquename(prefix=csvcol3_);
|
|
172
|
+
/* next, export data */
|
|
173
|
+
data _null_;
|
|
174
|
+
set &ds.;
|
|
175
|
+
file &outloc mod dlm=&delim dsd &outencoding lrecl=32767 termstr=&termstr;
|
|
176
|
+
if _n_=1 then &vmiss=' ';
|
|
177
|
+
%do i=1 %to &vcnt;
|
|
178
|
+
%let var=%scan(&varlist,&i);
|
|
179
|
+
%if &i=&vcnt %then %do;
|
|
180
|
+
%let vat=;
|
|
181
|
+
%let vcom=;
|
|
182
|
+
%end;
|
|
183
|
+
%if %mf_getvartype(&ds,&var)=N %then %do;
|
|
184
|
+
%if &headerformat = SASJS %then %do;
|
|
185
|
+
%let vcom=&delim;
|
|
186
|
+
%let fmttype=%sysfunc(mcf_getfmttype(%mf_getvarformat(&ds,&var)0));
|
|
187
|
+
%if &fmttype=DATE %then %let vfmt=DATE9.;
|
|
188
|
+
%else %if &fmttype=DATETIME %then %let vfmt=E8601DT26.6;
|
|
189
|
+
%else %if &fmttype=TIME %then %let vfmt=TIME12.;
|
|
190
|
+
%else %do;
|
|
191
|
+
%let vfmt=;
|
|
192
|
+
%let vcom=;
|
|
193
|
+
%end;
|
|
194
|
+
%end;
|
|
195
|
+
%else %let vcom=;
|
|
196
|
+
|
|
197
|
+
/* must use period - in order to work in both 9.4 and Viya 3.5 */
|
|
198
|
+
if missing(&var) and &var ne %sysfunc(getoption(MISSING)) then do;
|
|
199
|
+
&vmiss=cats('.',&var);
|
|
200
|
+
put &vmiss &vat;
|
|
201
|
+
end;
|
|
202
|
+
else put &var &vfmt &vcom &vat;
|
|
203
|
+
|
|
204
|
+
%end;
|
|
205
|
+
%else %do;
|
|
206
|
+
%if &i ne &vcnt %then %let vcom=&delim;
|
|
207
|
+
put &var &&vlen&i &vcom &vat;
|
|
208
|
+
%end;
|
|
209
|
+
%end;
|
|
210
|
+
run;
|
|
211
|
+
|
|
212
|
+
%mend mp_ds2csv;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief A wrapper for mp_getddl.sas
|
|
4
|
+
@details In the next release, this will be the main version.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
<h4> SAS Macros </h4>
|
|
8
|
+
@li mp_getddl.sas
|
|
9
|
+
|
|
10
|
+
**/
|
|
11
|
+
|
|
12
|
+
%macro mp_ds2ddl(libds,fref=getddl,flavour=SAS,showlog=YES,schema=
|
|
13
|
+
,applydttm=NO
|
|
14
|
+
)/*/STORE SOURCE*/;
|
|
15
|
+
|
|
16
|
+
%local libref;
|
|
17
|
+
%let libds=%upcase(&libds);
|
|
18
|
+
%let libref=%scan(&libds,1,.);
|
|
19
|
+
%if &libref=&libds %then %let libds=WORK.&libds;
|
|
20
|
+
|
|
21
|
+
%mp_getddl(%scan(&libds,1,.)
|
|
22
|
+
,%scan(&libds,2,.)
|
|
23
|
+
,fref=&fref
|
|
24
|
+
,flavour=SAS
|
|
25
|
+
,showlog=&showlog
|
|
26
|
+
,schema=&schema
|
|
27
|
+
,applydttm=&applydttm
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
%mend mp_ds2ddl;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Converts every value in a dataset to formatted value
|
|
4
|
+
@details Converts every value to it's formatted value. All variables will
|
|
5
|
+
become character, and will be in the same order as the original dataset.
|
|
6
|
+
|
|
7
|
+
Lengths will be adjusted according to the format lengths, where applicable.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
|
|
11
|
+
%mp_ds2fmtds(sashelp.cars,work.cars)
|
|
12
|
+
%mp_ds2fmtds(sashelp.vallopt,vw_vallopt)
|
|
13
|
+
|
|
14
|
+
@param [in] libds The library.dataset to be converted
|
|
15
|
+
@param [out] outds The dataset to create.
|
|
16
|
+
|
|
17
|
+
<h4> SAS Macros </h4>
|
|
18
|
+
@li mf_existds.sas
|
|
19
|
+
|
|
20
|
+
<h4> Related Macros </h4>
|
|
21
|
+
@li mp_jsonout.sas
|
|
22
|
+
|
|
23
|
+
@version 9.2
|
|
24
|
+
@author Allan Bowe
|
|
25
|
+
**/
|
|
26
|
+
|
|
27
|
+
%macro mp_ds2fmtds(libds, outds
|
|
28
|
+
)/*/STORE SOURCE*/;
|
|
29
|
+
|
|
30
|
+
/* validations */
|
|
31
|
+
|
|
32
|
+
%if not %mf_existds(libds=&libds) %then %do;
|
|
33
|
+
%put %str(WARN)ING: &libds does not exist as either a VIEW or DATASET;
|
|
34
|
+
%return;
|
|
35
|
+
%end;
|
|
36
|
+
%if %index(&libds,.)=0 %then %let libds=WORK.&libds;
|
|
37
|
+
|
|
38
|
+
/* grab metadata */
|
|
39
|
+
proc contents noprint data=&libds
|
|
40
|
+
out=_data_(keep=name type length format formatl formatd varnum);
|
|
41
|
+
run;
|
|
42
|
+
proc sort;
|
|
43
|
+
by varnum;
|
|
44
|
+
run;
|
|
45
|
+
|
|
46
|
+
/* prepare formats and varnames */
|
|
47
|
+
data _null_;
|
|
48
|
+
set &syslast end=last;
|
|
49
|
+
name=upcase(name);
|
|
50
|
+
/* fix formats */
|
|
51
|
+
if type=2 or type=6 then do;
|
|
52
|
+
length fmt $49.;
|
|
53
|
+
if format='' then fmt=cats('$',length,'.');
|
|
54
|
+
else if formatl=0 then fmt=cats(format,'.');
|
|
55
|
+
else fmt=cats(format,formatl,'.');
|
|
56
|
+
newlen=max(formatl,length);
|
|
57
|
+
end;
|
|
58
|
+
else do;
|
|
59
|
+
if format='' then fmt='best.';
|
|
60
|
+
else if formatl=0 then fmt=cats(format,'.');
|
|
61
|
+
else if formatd=0 then fmt=cats(format,formatl,'.');
|
|
62
|
+
else fmt=cats(format,formatl,'.',formatd);
|
|
63
|
+
/* needs to be wide, for datetimes etc */
|
|
64
|
+
newlen=max(length,formatl,24);
|
|
65
|
+
end;
|
|
66
|
+
/* 32 char unique name */
|
|
67
|
+
newname='sasjs'!!substr(cats(put(md5(name),$hex32.)),1,27);
|
|
68
|
+
|
|
69
|
+
call symputx(cats('name',_n_),name,'l');
|
|
70
|
+
call symputx(cats('newname',_n_),newname,'l');
|
|
71
|
+
call symputx(cats('len',_n_),newlen,'l');
|
|
72
|
+
call symputx(cats('fmt',_n_),fmt,'l');
|
|
73
|
+
call symputx(cats('type',_n_),type,'l');
|
|
74
|
+
if last then call symputx('nobs',_n_,'l');
|
|
75
|
+
run;
|
|
76
|
+
|
|
77
|
+
/* clean up */
|
|
78
|
+
proc sql;
|
|
79
|
+
drop table &syslast;
|
|
80
|
+
|
|
81
|
+
%if &nobs=0 %then %do;
|
|
82
|
+
%put Dataset &libds has no columns!
|
|
83
|
+
data &outds;
|
|
84
|
+
set &libds;
|
|
85
|
+
run;
|
|
86
|
+
%return;
|
|
87
|
+
%end;
|
|
88
|
+
|
|
89
|
+
data &outds;
|
|
90
|
+
/* rename on entry */
|
|
91
|
+
set &libds(rename=(
|
|
92
|
+
%local i;
|
|
93
|
+
%do i=1 %to &nobs;
|
|
94
|
+
&&name&i=&&newname&i
|
|
95
|
+
%end;
|
|
96
|
+
));
|
|
97
|
+
%do i=1 %to &nobs;
|
|
98
|
+
length &&name&i $&&len&i;
|
|
99
|
+
&&name&i=left(put(&&newname&i,&&fmt&i));
|
|
100
|
+
drop &&newname&i;
|
|
101
|
+
%end;
|
|
102
|
+
if _error_ then call symputx('syscc',1012);
|
|
103
|
+
run;
|
|
104
|
+
|
|
105
|
+
%mend mp_ds2fmtds;
|