@sasjs/utils 2.49.0 → 2.49.2
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 +262 -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_gitadd.sas +45 -0
- package/macros/mp_gitreleaseinfo.sas +74 -0
- package/macros/mp_gitstatus.sas +67 -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 +164 -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/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,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file mp_getddl.sas
|
|
3
|
+
@brief Extract DDL in various formats, by table or library
|
|
4
|
+
@details Data Definition Language relates to a set of SQL instructions used
|
|
5
|
+
to create tables in SAS or a database. The macro can be used at table or
|
|
6
|
+
library level. The default behaviour is to create DDL in SAS format.
|
|
7
|
+
|
|
8
|
+
Note - views are not currently supported.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
|
|
12
|
+
data test(index=(pk=(x y)/unique /nomiss));
|
|
13
|
+
x=1;
|
|
14
|
+
y='blah';
|
|
15
|
+
label x='blah';
|
|
16
|
+
run;
|
|
17
|
+
proc sql; describe table &syslast;
|
|
18
|
+
%mp_getddl(work,test,flavour=tsql,showlog=YES)
|
|
19
|
+
|
|
20
|
+
<h4> SAS Macros </h4>
|
|
21
|
+
@li mf_existfileref.sas
|
|
22
|
+
@li mf_getvarcount.sas
|
|
23
|
+
@li mp_getconstraints.sas
|
|
24
|
+
|
|
25
|
+
@param lib libref of the library to create DDL for. Should be assigned.
|
|
26
|
+
@param ds dataset to create ddl for (optional)
|
|
27
|
+
@param fref= the fileref to which to _append_ the DDL. If it does not exist,
|
|
28
|
+
it will be created.
|
|
29
|
+
@param flavour= The type of DDL to create (default=SAS). Supported=TSQL
|
|
30
|
+
@param showlog= Set to YES to show the DDL in the log
|
|
31
|
+
@param schema= Choose a preferred schema name (default is to use actual schema
|
|
32
|
+
,else libref)
|
|
33
|
+
@param applydttm= for non SAS DDL, choose if columns are created with native
|
|
34
|
+
datetime2 format or regular decimal type
|
|
35
|
+
@version 9.3
|
|
36
|
+
@author Allan Bowe
|
|
37
|
+
**/
|
|
38
|
+
|
|
39
|
+
%macro mp_getddl(libref,ds,fref=getddl,flavour=SAS,showlog=NO,schema=
|
|
40
|
+
,applydttm=NO
|
|
41
|
+
)/*/STORE SOURCE*/;
|
|
42
|
+
|
|
43
|
+
/* check fileref is assigned */
|
|
44
|
+
%if %mf_existfileref(&fref)=0 %then %do;
|
|
45
|
+
filename &fref temp ;
|
|
46
|
+
%end;
|
|
47
|
+
|
|
48
|
+
%if %length(&libref)=0 %then %let libref=WORK;
|
|
49
|
+
%let flavour=%upcase(&flavour);
|
|
50
|
+
|
|
51
|
+
proc sql noprint;
|
|
52
|
+
create table _data_ as
|
|
53
|
+
select * from dictionary.tables
|
|
54
|
+
where upcase(libname)="%upcase(&libref)"
|
|
55
|
+
and memtype='DATA' /* views not currently supported */
|
|
56
|
+
%if %length(&ds)>0 %then %do;
|
|
57
|
+
and upcase(memname)="%upcase(&ds)"
|
|
58
|
+
%end;
|
|
59
|
+
;
|
|
60
|
+
%local tabinfo; %let tabinfo=&syslast;
|
|
61
|
+
|
|
62
|
+
create table _data_ as
|
|
63
|
+
select * from dictionary.columns
|
|
64
|
+
where upcase(libname)="%upcase(&libref)"
|
|
65
|
+
%if %length(&ds)>0 %then %do;
|
|
66
|
+
and upcase(memname)="%upcase(&ds)"
|
|
67
|
+
%end;
|
|
68
|
+
;
|
|
69
|
+
%local colinfo; %let colinfo=&syslast;
|
|
70
|
+
|
|
71
|
+
%local dsnlist;
|
|
72
|
+
select distinct upcase(memname) into: dsnlist
|
|
73
|
+
separated by ' '
|
|
74
|
+
from &syslast
|
|
75
|
+
;
|
|
76
|
+
|
|
77
|
+
create table _data_ as
|
|
78
|
+
select * from dictionary.indexes
|
|
79
|
+
where upcase(libname)="%upcase(&libref)"
|
|
80
|
+
%if %length(&ds)>0 %then %do;
|
|
81
|
+
and upcase(memname)="%upcase(&ds)"
|
|
82
|
+
%end;
|
|
83
|
+
order by idxusage, indxname, indxpos
|
|
84
|
+
;
|
|
85
|
+
%local idxinfo; %let idxinfo=&syslast;
|
|
86
|
+
|
|
87
|
+
/* Extract all Primary Key and Unique data constraints */
|
|
88
|
+
%mp_getconstraints(lib=%upcase(&libref),ds=%upcase(&ds),outds=_data_)
|
|
89
|
+
%local colconst; %let colconst=&syslast;
|
|
90
|
+
|
|
91
|
+
%macro addConst();
|
|
92
|
+
%global constraints_used;
|
|
93
|
+
data _null_;
|
|
94
|
+
length ctype $11 constraint_name_orig $256 constraints_used $5000;
|
|
95
|
+
set &colconst(
|
|
96
|
+
where=(table_name="&curds" and constraint_type in ('PRIMARY','UNIQUE'))
|
|
97
|
+
) end=last;
|
|
98
|
+
file &fref mod;
|
|
99
|
+
by constraint_type constraint_name;
|
|
100
|
+
retain constraints_used;
|
|
101
|
+
constraint_name_orig=constraint_name;
|
|
102
|
+
if upcase(strip(constraint_type)) = 'PRIMARY' then ctype='PRIMARY KEY';
|
|
103
|
+
else ctype=strip(constraint_type);
|
|
104
|
+
%if &flavour=TSQL %then %do;
|
|
105
|
+
column_name=catt('[',column_name,']');
|
|
106
|
+
constraint_name=catt('[',constraint_name,']');
|
|
107
|
+
%end;
|
|
108
|
+
%else %if &flavour=PGSQL %then %do;
|
|
109
|
+
column_name=catt('"',column_name,'"');
|
|
110
|
+
constraint_name=catt('"',constraint_name,'"');
|
|
111
|
+
%end;
|
|
112
|
+
if first.constraint_name then do;
|
|
113
|
+
constraints_used = catx(' ', constraints_used, constraint_name_orig);
|
|
114
|
+
put " ,CONSTRAINT " constraint_name ctype "(" ;
|
|
115
|
+
put ' ' column_name;
|
|
116
|
+
end;
|
|
117
|
+
else put ' ,' column_name;
|
|
118
|
+
if last.constraint_name then do;
|
|
119
|
+
put " )";
|
|
120
|
+
call symput('constraints_used',strip(constraints_used));
|
|
121
|
+
end;
|
|
122
|
+
run;
|
|
123
|
+
%put &=constraints_used;
|
|
124
|
+
%mend addConst;
|
|
125
|
+
|
|
126
|
+
data _null_;
|
|
127
|
+
file &fref mod;
|
|
128
|
+
put "/* DDL generated by &sysuserid on %sysfunc(datetime(),datetime19.) */";
|
|
129
|
+
run;
|
|
130
|
+
|
|
131
|
+
%local x curds;
|
|
132
|
+
%if &flavour=SAS %then %do;
|
|
133
|
+
%do x=1 %to %sysfunc(countw(&dsnlist));
|
|
134
|
+
%let curds=%scan(&dsnlist,&x);
|
|
135
|
+
data _null_;
|
|
136
|
+
file &fref mod;
|
|
137
|
+
put "/* SAS Flavour DDL for %upcase(&libref).&curds */";
|
|
138
|
+
put "proc sql;";
|
|
139
|
+
run;
|
|
140
|
+
data _null_;
|
|
141
|
+
file &fref mod;
|
|
142
|
+
length lab $1024 typ $20;
|
|
143
|
+
set &colinfo (where=(upcase(memname)="&curds")) end=last;
|
|
144
|
+
|
|
145
|
+
if _n_=1 then do;
|
|
146
|
+
if memtype='DATA' then do;
|
|
147
|
+
put "create table &libref..&curds(";
|
|
148
|
+
end;
|
|
149
|
+
else do;
|
|
150
|
+
/* just a placeholder - we filter out views at the top */
|
|
151
|
+
put "create view &libref..&curds(";
|
|
152
|
+
end;
|
|
153
|
+
put " "@@;
|
|
154
|
+
end;
|
|
155
|
+
else put " ,"@@;
|
|
156
|
+
if length(format)>1 then fmt=" format="!!cats(format);
|
|
157
|
+
if length(label)>1 then
|
|
158
|
+
lab=" label="!!cats("'",tranwrd(label,"'","''"),"'");
|
|
159
|
+
if notnull='yes' then notnul=' not null';
|
|
160
|
+
if type='char' then typ=cats('char(',length,')');
|
|
161
|
+
else if length ne 8 then typ='num length='!!cats(length);
|
|
162
|
+
else typ='num';
|
|
163
|
+
put name typ fmt notnul lab;
|
|
164
|
+
run;
|
|
165
|
+
|
|
166
|
+
/* Extra step for data constraints */
|
|
167
|
+
%addConst()
|
|
168
|
+
|
|
169
|
+
data _null_;
|
|
170
|
+
file &fref mod;
|
|
171
|
+
put ');';
|
|
172
|
+
run;
|
|
173
|
+
|
|
174
|
+
/* Create Unique Indexes, but only if they were not already defined within
|
|
175
|
+
the Constraints section. */
|
|
176
|
+
data _null_;
|
|
177
|
+
*length ds $128;
|
|
178
|
+
set &idxinfo(
|
|
179
|
+
where=(
|
|
180
|
+
memname="&curds"
|
|
181
|
+
and unique='yes'
|
|
182
|
+
and indxname not in (
|
|
183
|
+
%sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
);
|
|
187
|
+
file &fref mod;
|
|
188
|
+
by idxusage indxname;
|
|
189
|
+
/* ds=cats(libname,'.',memname); */
|
|
190
|
+
if first.indxname then do;
|
|
191
|
+
put 'CREATE UNIQUE INDEX ' indxname "ON &libref..&curds (" ;
|
|
192
|
+
put ' ' name ;
|
|
193
|
+
end;
|
|
194
|
+
else put ' ,' name ;
|
|
195
|
+
*else put ' ,' name ;
|
|
196
|
+
if last.indxname then do;
|
|
197
|
+
put ');';
|
|
198
|
+
end;
|
|
199
|
+
run;
|
|
200
|
+
|
|
201
|
+
/*
|
|
202
|
+
ods output IntegrityConstraints=ic;
|
|
203
|
+
proc contents data=testali out2=info;
|
|
204
|
+
run;
|
|
205
|
+
*/
|
|
206
|
+
%end;
|
|
207
|
+
%end;
|
|
208
|
+
%else %if &flavour=TSQL %then %do;
|
|
209
|
+
/* if schema does not exist, set to be same as libref */
|
|
210
|
+
%local schemaactual;
|
|
211
|
+
proc sql noprint;
|
|
212
|
+
select sysvalue into: schemaactual
|
|
213
|
+
from dictionary.libnames
|
|
214
|
+
where upcase(libname)="&libref" and engine='SQLSVR';
|
|
215
|
+
%let schema=%sysfunc(coalescec(&schemaactual,&schema,&libref));
|
|
216
|
+
|
|
217
|
+
%do x=1 %to %sysfunc(countw(&dsnlist));
|
|
218
|
+
%let curds=%scan(&dsnlist,&x);
|
|
219
|
+
data _null_;
|
|
220
|
+
file &fref mod;
|
|
221
|
+
put "/* TSQL Flavour DDL for &schema..&curds */";
|
|
222
|
+
data _null_;
|
|
223
|
+
file &fref mod;
|
|
224
|
+
set &colinfo (where=(upcase(memname)="&curds")) end=last;
|
|
225
|
+
if _n_=1 then do;
|
|
226
|
+
if memtype='DATA' then do;
|
|
227
|
+
put "create table [&schema].[&curds](";
|
|
228
|
+
end;
|
|
229
|
+
else do;
|
|
230
|
+
/* just a placeholder - we filter out views at the top */
|
|
231
|
+
put "create view [&schema].[&curds](";
|
|
232
|
+
end;
|
|
233
|
+
put " "@@;
|
|
234
|
+
end;
|
|
235
|
+
else put " ,"@@;
|
|
236
|
+
format=upcase(format);
|
|
237
|
+
if 1=0 then; /* dummy if */
|
|
238
|
+
%if &applydttm=YES %then %do;
|
|
239
|
+
else if format=:'DATETIME' then fmt='[datetime2](7) ';
|
|
240
|
+
%end;
|
|
241
|
+
else if type='num' then fmt='[decimal](18,2)';
|
|
242
|
+
else if length le 8000 then fmt='[varchar]('!!cats(length)!!')';
|
|
243
|
+
else fmt=cats('[varchar](max)');
|
|
244
|
+
if notnull='yes' then notnul=' NOT NULL';
|
|
245
|
+
put "[" name +(-1) "]" fmt notnul;
|
|
246
|
+
run;
|
|
247
|
+
|
|
248
|
+
/* Extra step for data constraints */
|
|
249
|
+
%addConst()
|
|
250
|
+
|
|
251
|
+
/* Create Unique Indexes, but only if they were not already defined within
|
|
252
|
+
the Constraints section. */
|
|
253
|
+
data _null_;
|
|
254
|
+
*length ds $128;
|
|
255
|
+
set &idxinfo(
|
|
256
|
+
where=(
|
|
257
|
+
memname="&curds"
|
|
258
|
+
and unique='yes'
|
|
259
|
+
and indxname not in (
|
|
260
|
+
%sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
);
|
|
264
|
+
file &fref mod;
|
|
265
|
+
by idxusage indxname;
|
|
266
|
+
*ds=cats(libname,'.',memname);
|
|
267
|
+
if first.indxname then do;
|
|
268
|
+
/* add nonclustered in case of multiple unique indexes */
|
|
269
|
+
put ' ,index [' indxname +(-1) '] UNIQUE NONCLUSTERED (';
|
|
270
|
+
put ' [' name +(-1) ']';
|
|
271
|
+
end;
|
|
272
|
+
else put ' ,[' name +(-1) ']';
|
|
273
|
+
if last.indxname then do;
|
|
274
|
+
put ' )';
|
|
275
|
+
end;
|
|
276
|
+
run;
|
|
277
|
+
|
|
278
|
+
data _null_;
|
|
279
|
+
file &fref mod;
|
|
280
|
+
put ')';
|
|
281
|
+
put 'GO';
|
|
282
|
+
run;
|
|
283
|
+
|
|
284
|
+
/* add extended properties for labels */
|
|
285
|
+
data _null_;
|
|
286
|
+
file &fref mod;
|
|
287
|
+
length nm $64 lab $1024;
|
|
288
|
+
set &colinfo (where=(upcase(memname)="&curds" and label ne '')) end=last;
|
|
289
|
+
nm=cats("N'",tranwrd(name,"'","''"),"'");
|
|
290
|
+
lab=cats("N'",tranwrd(label,"'","''"),"'");
|
|
291
|
+
put ' ';
|
|
292
|
+
put "EXEC sys.sp_addextendedproperty ";
|
|
293
|
+
put " @name=N'MS_Description',@value=" lab ;
|
|
294
|
+
put " ,@level0type=N'SCHEMA',@level0name=N'&schema' ";
|
|
295
|
+
put " ,@level1type=N'TABLE',@level1name=N'&curds'";
|
|
296
|
+
put " ,@level2type=N'COLUMN',@level2name=" nm ;
|
|
297
|
+
if last then put 'GO';
|
|
298
|
+
run;
|
|
299
|
+
%end;
|
|
300
|
+
%end;
|
|
301
|
+
%else %if &flavour=PGSQL %then %do;
|
|
302
|
+
/* if schema does not exist, set to be same as libref */
|
|
303
|
+
%local schemaactual;
|
|
304
|
+
proc sql noprint;
|
|
305
|
+
select sysvalue into: schemaactual
|
|
306
|
+
from dictionary.libnames
|
|
307
|
+
where upcase(libname)="&libref" and engine='POSTGRES';
|
|
308
|
+
%let schema=%sysfunc(coalescec(&schemaactual,&schema,&libref));
|
|
309
|
+
data _null_;
|
|
310
|
+
file &fref mod;
|
|
311
|
+
put "CREATE SCHEMA &schema;";
|
|
312
|
+
%do x=1 %to %sysfunc(countw(&dsnlist));
|
|
313
|
+
%let curds=%scan(&dsnlist,&x);
|
|
314
|
+
%local curdsvarcount;
|
|
315
|
+
%let curdsvarcount=%mf_getvarcount(&libref..&curds);
|
|
316
|
+
%if &curdsvarcount>1600 %then %do;
|
|
317
|
+
data _null_;
|
|
318
|
+
file &fref mod;
|
|
319
|
+
put "/* &libref..&curds contains &curdsvarcount vars */";
|
|
320
|
+
put "/* Postgres cannot create tables with over 1600 vars */";
|
|
321
|
+
put "/* No DDL will be generated for this table";
|
|
322
|
+
run;
|
|
323
|
+
%end;
|
|
324
|
+
%else %do;
|
|
325
|
+
data _null_;
|
|
326
|
+
file &fref mod;
|
|
327
|
+
put "/* Postgres Flavour DDL for &schema..&curds */";
|
|
328
|
+
data _null_;
|
|
329
|
+
file &fref mod;
|
|
330
|
+
set &colinfo (where=(upcase(memname)="&curds")) end=last;
|
|
331
|
+
length fmt $32;
|
|
332
|
+
if _n_=1 then do;
|
|
333
|
+
if memtype='DATA' then do;
|
|
334
|
+
put "CREATE TABLE &schema..&curds (";
|
|
335
|
+
end;
|
|
336
|
+
else do;
|
|
337
|
+
/* just a placeholder - we filter out views at the top */
|
|
338
|
+
put "CREATE VIEW &schema..&curds (";
|
|
339
|
+
end;
|
|
340
|
+
put " "@@;
|
|
341
|
+
end;
|
|
342
|
+
else put " ,"@@;
|
|
343
|
+
format=upcase(format);
|
|
344
|
+
if 1=0 then; /* dummy if */
|
|
345
|
+
%if &applydttm=YES %then %do;
|
|
346
|
+
else if format=:'DATETIME' then fmt=' TIMESTAMP ';
|
|
347
|
+
%end;
|
|
348
|
+
else if type='num' then fmt=' DOUBLE PRECISION';
|
|
349
|
+
else fmt='VARCHAR('!!cats(length)!!')';
|
|
350
|
+
if notnull='yes' then notnul=' NOT NULL';
|
|
351
|
+
/* quote column names in case they represent reserved words */
|
|
352
|
+
name2=quote(trim(name));
|
|
353
|
+
put name2 fmt notnul;
|
|
354
|
+
run;
|
|
355
|
+
|
|
356
|
+
/* Extra step for data constraints */
|
|
357
|
+
%addConst()
|
|
358
|
+
|
|
359
|
+
data _null_;
|
|
360
|
+
file &fref mod;
|
|
361
|
+
put ');';
|
|
362
|
+
run;
|
|
363
|
+
|
|
364
|
+
/* Create Unique Indexes, but only if they were not already defined within
|
|
365
|
+
the Constraints section. */
|
|
366
|
+
data _null_;
|
|
367
|
+
*length ds $128;
|
|
368
|
+
set &idxinfo(
|
|
369
|
+
where=(
|
|
370
|
+
memname="&curds"
|
|
371
|
+
and unique='yes'
|
|
372
|
+
and indxname not in (
|
|
373
|
+
%sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
|
|
374
|
+
)
|
|
375
|
+
)
|
|
376
|
+
);
|
|
377
|
+
file &fref mod;
|
|
378
|
+
by idxusage indxname;
|
|
379
|
+
if first.indxname then do;
|
|
380
|
+
put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds(";
|
|
381
|
+
put ' "' name +(-1) '"' ;
|
|
382
|
+
end;
|
|
383
|
+
else put ' ,"' name +(-1) '"';
|
|
384
|
+
if last.indxname then do;
|
|
385
|
+
put ');';
|
|
386
|
+
end;
|
|
387
|
+
run;
|
|
388
|
+
%end;
|
|
389
|
+
%end;
|
|
390
|
+
%end;
|
|
391
|
+
%if %upcase(&showlog)=YES %then %do;
|
|
392
|
+
options ps=max;
|
|
393
|
+
data _null_;
|
|
394
|
+
infile &fref;
|
|
395
|
+
input;
|
|
396
|
+
putlog _infile_;
|
|
397
|
+
run;
|
|
398
|
+
%end;
|
|
399
|
+
|
|
400
|
+
%mend mp_getddl;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Export format definitions
|
|
4
|
+
@details Formats are exported from the first (if any) catalog entry in the
|
|
5
|
+
FMTSEARCH path.
|
|
6
|
+
|
|
7
|
+
Formats are taken from the library / dataset reference and / or a static
|
|
8
|
+
format list.
|
|
9
|
+
|
|
10
|
+
Example usage:
|
|
11
|
+
|
|
12
|
+
%mp_getformats(lib=sashelp,ds=prdsale,outsummary=work.dictable)
|
|
13
|
+
|
|
14
|
+
@param [in] lib= (0) The libref for which to return formats.
|
|
15
|
+
@todo Enable exporting of formats for an entire library
|
|
16
|
+
@param [in] ds= (0) The dataset from which to obtain format definitions
|
|
17
|
+
@param [in] fmtlist= (0) A list of additional format names
|
|
18
|
+
@param [out] outsummary= (work.mp_getformats_summary) Output dataset
|
|
19
|
+
containing summary definitions - structure taken from dictionary.formats as
|
|
20
|
+
follows:
|
|
21
|
+
|
|
22
|
+
|libname:$8.|memname:$32.|path:$1024.|objname:$32.|fmtname:$32.|fmttype:$1.|source:$1.|minw:best.|mind:best.|maxw:best.|maxd:best.|defw:best.|defd:best.|
|
|
23
|
+
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
24
|
+
| | | | |$|F|B|1|0|32767|0|1|0|
|
|
25
|
+
| | | | |$|I|B|1|0|32767|0|1|0|
|
|
26
|
+
|` `|` `|/opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe|UWIANYDT|$ANYDTIF|I|U|1|0|60|0|19|0|
|
|
27
|
+
| | |/opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe|UWFASCII|$ASCII|F|U|1|0|32767|0|1|0|
|
|
28
|
+
| | |/opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe|UWIASCII|$ASCII|I|U|1|0|32767|0|1|0|
|
|
29
|
+
| | |/opt/sas/sas9/SASHome/SASFoundation/9.4/sasexe|UWFBASE6|$BASE64X|F|U|1|0|32767|0|1|0|
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@param [out] outdetail= (0) Provide an output dataset in which to export all
|
|
33
|
+
the custom format definitions (from proc format CNTLOUT). Definitions:
|
|
34
|
+
https://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/viewer.htm#a002473477.htm
|
|
35
|
+
Sample data:
|
|
36
|
+
|
|
37
|
+
|FMTNAME:$32.|START:$16.|END:$16.|LABEL:$256.|MIN:best.|MAX:best.|DEFAULT:best.|LENGTH:best.|FUZZ:best.|PREFIX:$2.|MULT:best.|FILL:$1.|NOEDIT:best.|TYPE:$1.|SEXCL:$1.|EEXCL:$1.|HLO:$13.|DECSEP:$1.|DIG3SEP:$1.|DATATYPE:$8.|LANGUAGE:$8.|
|
|
38
|
+
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
39
|
+
|`WHICHPATH `|`0 `|`0 `|`path1 `|`1 `|`40 `|`28 `|`28 `|`1E-12 `|` `|`0 `|` `|`0 `|`N `|`N `|`N `|` `|` `|` `|` `|` `|
|
|
40
|
+
|`WHICHPATH `|`**OTHER** `|`**OTHER** `|`big fat problem if not path1 `|`1 `|`40 `|`28 `|`28 `|`1E-12 `|` `|`0 `|` `|`0 `|`N `|`N `|`N `|`O `|` `|` `|` `|` `|
|
|
41
|
+
|
|
42
|
+
<h4> SAS Macros </h4>
|
|
43
|
+
@li mddl_sas_cntlout.sas
|
|
44
|
+
@li mf_dedup.sas
|
|
45
|
+
@li mf_getfmtlist.sas
|
|
46
|
+
@li mf_getfmtname.sas
|
|
47
|
+
@li mf_getquotedstr.sas
|
|
48
|
+
@li mf_getuniquename.sas
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
<h4> Related Macros </h4>
|
|
52
|
+
@li mp_applyformats.sas
|
|
53
|
+
@li mp_getformats.test.sas
|
|
54
|
+
|
|
55
|
+
@version 9.2
|
|
56
|
+
@author Allan Bowe
|
|
57
|
+
|
|
58
|
+
**/
|
|
59
|
+
|
|
60
|
+
%macro mp_getformats(lib=0
|
|
61
|
+
,ds=0
|
|
62
|
+
,fmtlist=0
|
|
63
|
+
,outsummary=work.mp_getformats_summary
|
|
64
|
+
,outdetail=0
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
%local i fmt allfmts tempds fmtcnt;
|
|
68
|
+
|
|
69
|
+
%if "&fmtlist" ne "0" %then %do i=1 %to %sysfunc(countw(&fmtlist,,%str( )));
|
|
70
|
+
/* ensure format list contains format _name_ only */
|
|
71
|
+
%let fmt=%scan(&fmtlist,&i,%str( ));
|
|
72
|
+
%let fmt=%mf_getfmtname(&fmt);
|
|
73
|
+
%let allfmts=&allfmts &fmt;
|
|
74
|
+
%end;
|
|
75
|
+
|
|
76
|
+
%if &ds=0 and &lib ne 0 %then %do;
|
|
77
|
+
/* grab formats from library */
|
|
78
|
+
/* to do */
|
|
79
|
+
%end;
|
|
80
|
+
%else %if &ds ne 0 and &lib ne 0 %then %do;
|
|
81
|
+
/* grab formats from dataset */
|
|
82
|
+
%let allfmts=%mf_getfmtlist(&lib..&ds) &allfmts;
|
|
83
|
+
%end;
|
|
84
|
+
|
|
85
|
+
/* ensure list is unique */
|
|
86
|
+
%let allfmts=%mf_dedup(%upcase(&allfmts));
|
|
87
|
+
|
|
88
|
+
/* create summary table */
|
|
89
|
+
%if %index(&outsummary,.)=0 %then %let outsummary=WORK.&outsummary;
|
|
90
|
+
proc sql;
|
|
91
|
+
create table &outsummary as
|
|
92
|
+
select * from dictionary.formats
|
|
93
|
+
where fmtname in (%mf_getquotedstr(&allfmts,quote=D))
|
|
94
|
+
and fmttype='F';
|
|
95
|
+
|
|
96
|
+
%if "&outdetail" ne "0" %then %do;
|
|
97
|
+
/* ensure base table always exists */
|
|
98
|
+
%mddl_sas_cntlout(libds=&outdetail)
|
|
99
|
+
/* grab the location of each format */
|
|
100
|
+
%let fmtcnt=0;
|
|
101
|
+
data _null_;
|
|
102
|
+
set &outsummary;
|
|
103
|
+
if not missing(libname);
|
|
104
|
+
x+1;
|
|
105
|
+
call symputx(cats('fmtloc',x),cats(libname,'.',memname),'l');
|
|
106
|
+
call symputx(cats('fmtname',x),fmtname,'l');
|
|
107
|
+
call symputx('fmtcnt',x,'l');
|
|
108
|
+
run;
|
|
109
|
+
/* export each format and append to the output table */
|
|
110
|
+
%let tempds=%mf_getuniquename(prefix=mp_getformats);
|
|
111
|
+
%do i=1 %to &fmtcnt;
|
|
112
|
+
proc format library=&&fmtloc&i CNTLOUT=&tempds;
|
|
113
|
+
select &&fmtname&i;
|
|
114
|
+
run;
|
|
115
|
+
data &tempds;
|
|
116
|
+
if 0 then set &outdetail;
|
|
117
|
+
set &tempds;
|
|
118
|
+
run;
|
|
119
|
+
proc append base=&outdetail data=&tempds ;
|
|
120
|
+
run;
|
|
121
|
+
%end;
|
|
122
|
+
%end;
|
|
123
|
+
|
|
124
|
+
%mend mp_getformats;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
@file
|
|
3
|
+
@brief Scans a dataset to find the max length of the variable values
|
|
4
|
+
@details
|
|
5
|
+
This macro will scan a base dataset and produce an output dataset with two
|
|
6
|
+
columns:
|
|
7
|
+
|
|
8
|
+
- NAME Name of the base dataset column
|
|
9
|
+
- MAXLEN Maximum length of the data contained therein.
|
|
10
|
+
|
|
11
|
+
Character fields are often allocated very large widths (eg 32000) of which the
|
|
12
|
+
maximum value is likely to be much narrower. Identifying such cases can be
|
|
13
|
+
helpful in the following scenarios:
|
|
14
|
+
|
|
15
|
+
@li Enabling a HTML table to be appropriately sized (`num2char=YES`)
|
|
16
|
+
@li Reducing the size of a dataset to save on storage (mp_ds2squeeze.sas)
|
|
17
|
+
@li Identifying columns containing nothing but missing values (`MAXLEN=0` in
|
|
18
|
+
the output table)
|
|
19
|
+
|
|
20
|
+
If the entire column is made up of (non-special) missing values then a value
|
|
21
|
+
of 0 is returned.
|
|
22
|
+
|
|
23
|
+
Usage:
|
|
24
|
+
|
|
25
|
+
%mp_getmaxvarlengths(sashelp.class,outds=work.myds)
|
|
26
|
+
|
|
27
|
+
@param [in] libds Two part dataset (or view) reference.
|
|
28
|
+
@param [in] num2char= (NO) When set to NO, numeric fields are sized according
|
|
29
|
+
to the number of bytes used (or set to zero in the case of non-special
|
|
30
|
+
missings). When YES, the numeric field is converted to character (using the
|
|
31
|
+
format, if available), and that is sized instead, using `lengthn()`.
|
|
32
|
+
@param [out] outds= The output dataset to create, eg:
|
|
33
|
+
|NAME:$8.|MAXLEN:best.|
|
|
34
|
+
|---|---|
|
|
35
|
+
|`Name `|`7 `|
|
|
36
|
+
|`Sex `|`1 `|
|
|
37
|
+
|`Age `|`3 `|
|
|
38
|
+
|`Height `|`8 `|
|
|
39
|
+
|`Weight `|`3 `|
|
|
40
|
+
|
|
41
|
+
<h4> SAS Macros </h4>
|
|
42
|
+
@li mcf_length.sas
|
|
43
|
+
@li mf_getuniquename.sas
|
|
44
|
+
@li mf_getvarcount.sas
|
|
45
|
+
@li mf_getvarlist.sas
|
|
46
|
+
@li mf_getvartype.sas
|
|
47
|
+
@li mf_getvarformat.sas
|
|
48
|
+
|
|
49
|
+
@version 9.2
|
|
50
|
+
@author Allan Bowe
|
|
51
|
+
|
|
52
|
+
<h4> Related Macros </h4>
|
|
53
|
+
@li mp_ds2squeeze.sas
|
|
54
|
+
@li mp_getmaxvarlengths.test.sas
|
|
55
|
+
|
|
56
|
+
**/
|
|
57
|
+
|
|
58
|
+
%macro mp_getmaxvarlengths(
|
|
59
|
+
libds
|
|
60
|
+
,num2char=NO
|
|
61
|
+
,outds=work.mp_getmaxvarlengths
|
|
62
|
+
)/*/STORE SOURCE*/;
|
|
63
|
+
|
|
64
|
+
%local vars prefix x var fmt srcds;
|
|
65
|
+
%let vars=%mf_getvarlist(libds=&libds);
|
|
66
|
+
%let prefix=%substr(%mf_getuniquename(),1,25);
|
|
67
|
+
%let num2char=%upcase(&num2char);
|
|
68
|
+
|
|
69
|
+
%if &num2char=NO %then %do;
|
|
70
|
+
/* compile length function for numeric fields */
|
|
71
|
+
%mcf_length(wrap=YES, insert_cmplib=YES)
|
|
72
|
+
%end;
|
|
73
|
+
|
|
74
|
+
%if &num2char=NO
|
|
75
|
+
and ("%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5")
|
|
76
|
+
and %mf_getvarcount(&libds,typefilter=N) gt 0
|
|
77
|
+
%then %do;
|
|
78
|
+
/* custom functions not supported in summary operations */
|
|
79
|
+
%let srcds=%mf_getuniquename();
|
|
80
|
+
data &srcds/view=&srcds;
|
|
81
|
+
set &libds;
|
|
82
|
+
%do x=1 %to %sysfunc(countw(&vars,%str( )));
|
|
83
|
+
%let var=%scan(&vars,&x);
|
|
84
|
+
%if %mf_getvartype(&libds,&var)=N %then %do;
|
|
85
|
+
&prefix.&x=mcf_length(&var);
|
|
86
|
+
%end;
|
|
87
|
+
%end;
|
|
88
|
+
run;
|
|
89
|
+
%end;
|
|
90
|
+
%else %let srcds=&libds;
|
|
91
|
+
|
|
92
|
+
proc sql;
|
|
93
|
+
create table &outds (rename=(
|
|
94
|
+
%do x=1 %to %sysfunc(countw(&vars,%str( )));
|
|
95
|
+
&prefix.&x=%scan(&vars,&x)
|
|
96
|
+
%end;
|
|
97
|
+
))
|
|
98
|
+
as select
|
|
99
|
+
%do x=1 %to %sysfunc(countw(&vars,%str( )));
|
|
100
|
+
%let var=%scan(&vars,&x);
|
|
101
|
+
%if &x>1 %then ,;
|
|
102
|
+
%if %mf_getvartype(&libds,&var)=C %then %do;
|
|
103
|
+
max(lengthn(&var)) as &prefix.&x
|
|
104
|
+
%end;
|
|
105
|
+
%else %if &num2char=YES %then %do;
|
|
106
|
+
%let fmt=%mf_getvarformat(&libds,&var);
|
|
107
|
+
%put fmt=&fmt;
|
|
108
|
+
%if %str(&fmt)=%str() %then %do;
|
|
109
|
+
max(lengthn(cats(&var))) as &prefix.&x
|
|
110
|
+
%end;
|
|
111
|
+
%else %do;
|
|
112
|
+
max(lengthn(put(&var,&fmt))) as &prefix.&x
|
|
113
|
+
%end;
|
|
114
|
+
%end;
|
|
115
|
+
%else %do;
|
|
116
|
+
%if "%substr(&sysver,1,1)"="4" or "%substr(&sysver,1,1)"="5" %then %do;
|
|
117
|
+
max(&prefix.&x) as &prefix.&x
|
|
118
|
+
%end;
|
|
119
|
+
%else %do;
|
|
120
|
+
max(mcf_length(&var)) as &prefix.&x
|
|
121
|
+
%end;
|
|
122
|
+
%end;
|
|
123
|
+
%end;
|
|
124
|
+
from &srcds;
|
|
125
|
+
|
|
126
|
+
proc transpose data=&outds
|
|
127
|
+
out=&outds(rename=(_name_=NAME COL1=MAXLEN));
|
|
128
|
+
run;
|
|
129
|
+
|
|
130
|
+
%mend mp_getmaxvarlengths;
|