1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-08 18:00:06 +00:00

Compare commits

...

8 Commits

8 changed files with 429 additions and 159 deletions

260
all.sas
View File

@@ -3438,15 +3438,16 @@ run;
%inc myref; %inc myref;
@param [in] ds The dataset to be exported @param [in] ds The dataset to be exported
@param [in] maxobs= (max) The max number of inserts to create
@param [out] outref= (0) The output fileref. If it does not exist, it is @param [out] outref= (0) The output fileref. If it does not exist, it is
created. If it does exist, new records are APPENDED. created. If it does exist, new records are APPENDED.
@param [out] outlib= (0) The library (or schema) in which the target table is @param [out] schema= (0) The library (or schema) in which the target table is
located. If not provided, is ignored. located. If not provided, is ignored.
@param [out] outds= (0) The output table to load. If not provided, will @param [out] outds= (0) The output table to load. If not provided, will
default to the table in the &ds parameter. default to the table in the &ds parameter.
@param [in] flavour= (BASE) The SQL flavour to be applied to the output. Valid @param [in] flavour= (SAS) The SQL flavour to be applied to the output. Valid
options: options:
@li BASE (default) - suitable for regular proc sql @li SAS (default) - suitable for regular proc sql
@li PGSQL - Used for Postgres databases @li PGSQL - Used for Postgres databases
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@@ -3459,7 +3460,7 @@ run;
@author Allan Bowe (credit mjsq) @author Allan Bowe (credit mjsq)
**/ **/
%macro mp_ds2inserts(ds, outref=0,outlib=0,outds=0,flavour=BASE %macro mp_ds2inserts(ds, outref=0,schema=0,outds=0,flavour=SAS,maxobs=max
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not %sysfunc(exist(&ds)) %then %do; %if not %sysfunc(exist(&ds)) %then %do;
@@ -3475,7 +3476,7 @@ run;
%if %index(&ds,.)=0 %then %let ds=WORK.&ds; %if %index(&ds,.)=0 %then %let ds=WORK.&ds;
%let flavour=%upcase(&flavour); %let flavour=%upcase(&flavour);
%if &flavour ne BASE and &flavour ne PGSQL %then %do; %if &flavour ne SAS and &flavour ne PGSQL %then %do;
%put %str(WAR)NING: &flavour is not supported; %put %str(WAR)NING: &flavour is not supported;
%return; %return;
%end; %end;
@@ -3488,8 +3489,8 @@ run;
filename &outref temp lrecl=66000; filename &outref temp lrecl=66000;
%end; %end;
%if &outlib=0 %then %let outlib=; %if &schema=0 %then %let schema=;
%else %let outlib=&outlib..; %else %let schema=&schema..;
%if &outds=0 %then %let outds=%scan(&ds,2,.); %if &outds=0 %then %let outds=%scan(&ds,2,.);
@@ -3508,8 +3509,18 @@ select count(*) into: nobs TRIMMED from &ds;
%if &vars=0 %then %do; %if &vars=0 %then %do;
data _null_; data _null_;
file &outref mod; file &outref mod;
put "/* No columns found in &ds */"; put "/* No columns found in &schema.&ds */";
run; run;
%return;
%end;
%else %if &vars>1600 and &flavour=PGSQL %then %do;
data _null_;
file &fref mod;
put "/* &schema.&ds contains &vars vars */";
put "/* Postgres cannot handle tables with over 1600 vars */";
put "/* No inserts will be generated for this table */";
run;
%return;
%end; %end;
%local varlist varlistcomma; %local varlist varlistcomma;
@@ -3519,8 +3530,11 @@ select count(*) into: nobs TRIMMED from &ds;
/* next, export data */ /* next, export data */
data _null_; data _null_;
file &outref mod ; file &outref mod ;
if _n_=1 then put "/* &outlib.&outds (&nobs rows, &vars columns) */"; if _n_=1 then put "/* &schema.&outds (&nobs rows, &vars columns) */";
set &ds; set &ds;
%if &maxobs ne max %then %do;
if _n_>&maxobs then stop;
%end;
length _____str $32767; length _____str $32767;
format _numeric_ best.; format _numeric_ best.;
format _character_ ; format _character_ ;
@@ -3529,13 +3543,13 @@ data _null_;
%let var=%scan(&varlist,&i); %let var=%scan(&varlist,&i);
%let vtype=%mf_getvartype(&ds,&var); %let vtype=%mf_getvartype(&ds,&var);
%if &i=1 %then %do; %if &i=1 %then %do;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put "insert into &outlib.&outds set "; put "insert into &schema.&outds set ";
put " &var="@; put " &var="@;
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
_____str=cats( _____str=cats(
"INSERT INTO &outlib.&outds (" "INSERT INTO &schema.&outds ("
,symget('varlistcomma') ,symget('varlistcomma')
,") VALUES (" ,") VALUES ("
); );
@@ -3544,7 +3558,7 @@ data _null_;
%end; %end;
%end; %end;
%else %do; %else %do;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put " ,&var="@; put " ,&var="@;
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
@@ -3552,7 +3566,7 @@ data _null_;
%end; %end;
%end; %end;
%if &vtype=N %then %do; %if &vtype=N %then %do;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put &var; put &var;
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
@@ -3565,7 +3579,7 @@ data _null_;
put _____str; put _____str;
%end; %end;
%end; %end;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put ';'; put ';';
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
@@ -4386,6 +4400,8 @@ run;
to create tables in SAS or a database. The macro can be used at table or to create tables in SAS or a database. The macro can be used at table or
library level. The default behaviour is to create DDL in SAS format. library level. The default behaviour is to create DDL in SAS format.
Note - views are not currently supported.
Usage: Usage:
data test(index=(pk=(x y)/unique /nomiss)); data test(index=(pk=(x y)/unique /nomiss));
@@ -4398,6 +4414,7 @@ run;
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_existfileref.sas @li mf_existfileref.sas
@li mf_getvarcount.sas
@li mp_getconstraints.sas @li mp_getconstraints.sas
@param lib libref of the library to create DDL for. Should be assigned. @param lib libref of the library to create DDL for. Should be assigned.
@@ -4419,8 +4436,8 @@ run;
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
/* check fileref is assigned */ /* check fileref is assigned */
%if %mf_existfileref(&outref)=0 %then %do; %if %mf_existfileref(&fref)=0 %then %do;
filename &outref temp ; filename &fref temp ;
%end; %end;
%if %length(&libref)=0 %then %let libref=WORK; %if %length(&libref)=0 %then %let libref=WORK;
@@ -4430,6 +4447,7 @@ proc sql noprint;
create table _data_ as create table _data_ as
select * from dictionary.tables select * from dictionary.tables
where upcase(libname)="%upcase(&libref)" where upcase(libname)="%upcase(&libref)"
and memtype='DATA' /* views not currently supported */
%if %length(&ds)>0 %then %do; %if %length(&ds)>0 %then %do;
and upcase(memname)="%upcase(&ds)" and upcase(memname)="%upcase(&ds)"
%end; %end;
@@ -4524,13 +4542,15 @@ run;
put "create table &libref..&curds("; put "create table &libref..&curds(";
end; end;
else do; else do;
/* just a placeholder - we filter out views at the top */
put "create view &libref..&curds("; put "create view &libref..&curds(";
end; end;
put " "@@; put " "@@;
end; end;
else put " ,"@@; else put " ,"@@;
if length(format)>1 then fmt=" format="!!cats(format); if length(format)>1 then fmt=" format="!!cats(format);
if length(label)>1 then lab=" label="!!quote(trim(label)); if length(label)>1 then
lab=" label="!!cats("'",tranwrd(label,"'","''"),"'");
if notnull='yes' then notnul=' not null'; if notnull='yes' then notnul=' not null';
if type='char' then typ=cats('char(',length,')'); if type='char' then typ=cats('char(',length,')');
else if length ne 8 then typ='num length='!!left(length); else if length ne 8 then typ='num length='!!left(length);
@@ -4602,6 +4622,7 @@ run;
put "create table [&schema].[&curds]("; put "create table [&schema].[&curds](";
end; end;
else do; else do;
/* just a placeholder - we filter out views at the top */
put "create view [&schema].[&curds]("; put "create view [&schema].[&curds](";
end; end;
put " "@@; put " "@@;
@@ -4685,71 +4706,81 @@ run;
put "CREATE SCHEMA &schema;"; put "CREATE SCHEMA &schema;";
%do x=1 %to %sysfunc(countw(&dsnlist)); %do x=1 %to %sysfunc(countw(&dsnlist));
%let curds=%scan(&dsnlist,&x); %let curds=%scan(&dsnlist,&x);
data _null_; %local curdsvarcount;
file &fref mod; %let curdsvarcount=%mf_getvarcount(&libref..&curds);
put "/* Postgres Flavour DDL for &schema..&curds */"; %if &curdsvarcount>1600 %then %do;
data _null_; data _null_;
file &fref mod; file &fref mod;
set &colinfo (where=(upcase(memname)="&curds")) end=last; put "/* &libref..&curds contains &curdsvarcount vars */";
length fmt $32; put "/* Postgres cannot create tables with over 1600 vars */";
if _n_=1 then do; put "/* No DDL will be generated for this table";
if memtype='DATA' then do; run;
put "CREATE TABLE &schema..&curds ("; %end;
%else %do;
data _null_;
file &fref mod;
put "/* Postgres Flavour DDL for &schema..&curds */";
data _null_;
file &fref mod;
set &colinfo (where=(upcase(memname)="&curds")) end=last;
length fmt $32;
if _n_=1 then do;
if memtype='DATA' then do;
put "CREATE TABLE &schema..&curds (";
end;
else do;
/* just a placeholder - we filter out views at the top */
put "CREATE VIEW &schema..&curds (";
end;
put " "@@;
end; end;
else do; else put " ,"@@;
put "CREATE VIEW &schema..&curds ("; format=upcase(format);
end; if 1=0 then; /* dummy if */
put " "@@; %if &applydttm=YES %then %do;
end; else if format=:'DATETIME' then fmt=' TIMESTAMP ';
else put " ,"@@; %end;
format=upcase(format); else if type='num' then fmt=' DOUBLE PRECISION';
if 1=0 then; /* dummy if */ else fmt='VARCHAR('!!cats(length)!!')';
%if &applydttm=YES %then %do; if notnull='yes' then notnul=' NOT NULL';
else if format=:'DATETIME' then fmt=' TIMESTAMP '; /* quote column names in case they represent reserved words */
%end; name2=quote(trim(name));
else if type='num' then fmt=' DOUBLE PRECISION'; put name2 fmt notnul;
else fmt='VARCHAR('!!cats(length)!!')'; run;
if notnull='yes' then notnul=' NOT NULL';
/* quote column names in case they represent reserved words */
name2=quote(trim(name));
put name2 fmt notnul;
run;
/* Extra step for data constraints */ /* Extra step for data constraints */
%addConst() %addConst()
data _null_; data _null_;
file &fref mod; file &fref mod;
put ');'; put ');';
run; run;
/* Create Unique Indexes, but only if they were not already defined within /* Create Unique Indexes, but only if they were not already defined within
the Constraints section. */ the Constraints section. */
data _null_; data _null_;
*length ds $128; *length ds $128;
set &idxinfo( set &idxinfo(
where=( where=(
memname="&curds" memname="&curds"
and unique='yes' and unique='yes'
and indxname not in ( and indxname not in (
%sysfunc(tranwrd("&constraints_used",%str( ),%str(","))) %sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
)
) )
) );
); file &fref mod;
file &fref mod; by idxusage indxname;
by idxusage indxname; if first.indxname then do;
/* ds=cats(libname,'.',memname); */
if first.indxname then do;
put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds("; put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds(";
put ' "' name +(-1) '"' ; put ' "' name +(-1) '"' ;
end; end;
else put ' ,"' name +(-1) '"'; else put ' ,"' name +(-1) '"';
*else put ' ,' name ; if last.indxname then do;
if last.indxname then do; put ');';
put ');'; end;
end; run;
run; %end;
%end; %end;
%end; %end;
%if %upcase(&showlog)=YES %then %do; %if %upcase(&showlog)=YES %then %do;
@@ -5158,8 +5189,7 @@ create table &outds (rename=(
@li mf_getvartype.sas @li mf_getvartype.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the name of the @param [in] salt= Provide a salt (could be, for instance, the dataset name)
dataset). Max 32 chars.
@param [out] outds= (work.mf_hashdataset) The output dataset to create. This @param [out] outds= (work.mf_hashdataset) The output dataset to create. This
will contain one column (hashkey) with one observation (a hex32. will contain one column (hashkey) with one observation (a hex32.
representation of the input hash) representation of the input hash)
@@ -5194,7 +5224,7 @@ create table &outds (rename=(
%let varlist=%mf_getvarlist(&libds); %let varlist=%mf_getvarlist(&libds);
data &outds(rename=(&keyvar=hashkey) keep=&keyvar); data &outds(rename=(&keyvar=hashkey) keep=&keyvar);
length &prevkeyvar &keyvar $32; length &prevkeyvar &keyvar $32;
retain &prevkeyvar "&salt"; retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
set &libds end=&lastvar; set &libds end=&lastvar;
/* hash should include previous row */ /* hash should include previous row */
&keyvar=put(md5(&prevkeyvar &keyvar=put(md5(&prevkeyvar
@@ -5524,6 +5554,78 @@ select distinct lowcase(memname)
%end; %end;
%mend mp_lib2cards;/** %mend mp_lib2cards;/**
@file
@brief Convert all data in a library to SQL insert statements
@details Gets list of members then calls the <code>%mp_ds2inserts()</code>
macro.
Usage:
%mp_getddl(sashelp, schema=work, fref=tempref)
%mp_lib2inserts(sashelp, schema=work, outref=tempref)
%inc tempref;
The output will be one file in the outref fileref.
<h4> SAS Macros </h4>
@li mp_ds2inserts.sas
@param [in] lib Library in which to convert all datasets to inserts
@param [in] flavour= (SAS) The SQL flavour to be applied to the output. Valid
options:
@li SAS (default) - suitable for regular proc sql
@li PGSQL - Used for Postgres databases
@param [in] maxobs= (max) The max number of observations (per table) to create
@param [out] outref= Output fileref in which to create the insert statements.
If it exists, it will be appended to, otherwise it will be created.
@param [out] schema= (0) The schema of the target database, or the libref.
@version 9.2
@author Allan Bowe
**/
%macro mp_lib2inserts(lib
,flavour=SAS
,outref=0
,schema=0
,maxobs=max
)/*/STORE SOURCE*/;
/* Find the tables */
%local x ds memlist;
proc sql noprint;
select distinct lowcase(memname)
into: memlist
separated by ' '
from dictionary.tables
where upcase(libname)="%upcase(&lib)"
and memtype='DATA'; /* exclude views */
%let flavour=%upcase(&flavour);
%if &flavour ne SAS and &flavour ne PGSQL %then %do;
%put %str(WAR)NING: &flavour is not supported;
%return;
%end;
/* create the inserts */
%do x=1 %to %sysfunc(countw(&memlist));
%let ds=%scan(&memlist,&x);
%mp_ds2inserts(&lib..&ds
,outref=&outref
,schema=&schema
,outds=&ds
,flavour=&flavour
,maxobs=&maxobs
)
%end;
%mend mp_lib2inserts;/**
@file @file
@brief Create a Markdown Table from a dataset @brief Create a Markdown Table from a dataset
@details A markdown table is a simple table representation for use in @details A markdown table is a simple table representation for use in

View File

@@ -14,15 +14,16 @@
%inc myref; %inc myref;
@param [in] ds The dataset to be exported @param [in] ds The dataset to be exported
@param [in] maxobs= (max) The max number of inserts to create
@param [out] outref= (0) The output fileref. If it does not exist, it is @param [out] outref= (0) The output fileref. If it does not exist, it is
created. If it does exist, new records are APPENDED. created. If it does exist, new records are APPENDED.
@param [out] outlib= (0) The library (or schema) in which the target table is @param [out] schema= (0) The library (or schema) in which the target table is
located. If not provided, is ignored. located. If not provided, is ignored.
@param [out] outds= (0) The output table to load. If not provided, will @param [out] outds= (0) The output table to load. If not provided, will
default to the table in the &ds parameter. default to the table in the &ds parameter.
@param [in] flavour= (BASE) The SQL flavour to be applied to the output. Valid @param [in] flavour= (SAS) The SQL flavour to be applied to the output. Valid
options: options:
@li BASE (default) - suitable for regular proc sql @li SAS (default) - suitable for regular proc sql
@li PGSQL - Used for Postgres databases @li PGSQL - Used for Postgres databases
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@@ -35,7 +36,7 @@
@author Allan Bowe (credit mjsq) @author Allan Bowe (credit mjsq)
**/ **/
%macro mp_ds2inserts(ds, outref=0,outlib=0,outds=0,flavour=BASE %macro mp_ds2inserts(ds, outref=0,schema=0,outds=0,flavour=SAS,maxobs=max
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
%if not %sysfunc(exist(&ds)) %then %do; %if not %sysfunc(exist(&ds)) %then %do;
@@ -51,7 +52,7 @@
%if %index(&ds,.)=0 %then %let ds=WORK.&ds; %if %index(&ds,.)=0 %then %let ds=WORK.&ds;
%let flavour=%upcase(&flavour); %let flavour=%upcase(&flavour);
%if &flavour ne BASE and &flavour ne PGSQL %then %do; %if &flavour ne SAS and &flavour ne PGSQL %then %do;
%put %str(WAR)NING: &flavour is not supported; %put %str(WAR)NING: &flavour is not supported;
%return; %return;
%end; %end;
@@ -64,8 +65,8 @@
filename &outref temp lrecl=66000; filename &outref temp lrecl=66000;
%end; %end;
%if &outlib=0 %then %let outlib=; %if &schema=0 %then %let schema=;
%else %let outlib=&outlib..; %else %let schema=&schema..;
%if &outds=0 %then %let outds=%scan(&ds,2,.); %if &outds=0 %then %let outds=%scan(&ds,2,.);
@@ -84,8 +85,18 @@ select count(*) into: nobs TRIMMED from &ds;
%if &vars=0 %then %do; %if &vars=0 %then %do;
data _null_; data _null_;
file &outref mod; file &outref mod;
put "/* No columns found in &ds */"; put "/* No columns found in &schema.&ds */";
run; run;
%return;
%end;
%else %if &vars>1600 and &flavour=PGSQL %then %do;
data _null_;
file &fref mod;
put "/* &schema.&ds contains &vars vars */";
put "/* Postgres cannot handle tables with over 1600 vars */";
put "/* No inserts will be generated for this table */";
run;
%return;
%end; %end;
%local varlist varlistcomma; %local varlist varlistcomma;
@@ -95,8 +106,11 @@ select count(*) into: nobs TRIMMED from &ds;
/* next, export data */ /* next, export data */
data _null_; data _null_;
file &outref mod ; file &outref mod ;
if _n_=1 then put "/* &outlib.&outds (&nobs rows, &vars columns) */"; if _n_=1 then put "/* &schema.&outds (&nobs rows, &vars columns) */";
set &ds; set &ds;
%if &maxobs ne max %then %do;
if _n_>&maxobs then stop;
%end;
length _____str $32767; length _____str $32767;
format _numeric_ best.; format _numeric_ best.;
format _character_ ; format _character_ ;
@@ -105,13 +119,13 @@ data _null_;
%let var=%scan(&varlist,&i); %let var=%scan(&varlist,&i);
%let vtype=%mf_getvartype(&ds,&var); %let vtype=%mf_getvartype(&ds,&var);
%if &i=1 %then %do; %if &i=1 %then %do;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put "insert into &outlib.&outds set "; put "insert into &schema.&outds set ";
put " &var="@; put " &var="@;
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
_____str=cats( _____str=cats(
"INSERT INTO &outlib.&outds (" "INSERT INTO &schema.&outds ("
,symget('varlistcomma') ,symget('varlistcomma')
,") VALUES (" ,") VALUES ("
); );
@@ -120,7 +134,7 @@ data _null_;
%end; %end;
%end; %end;
%else %do; %else %do;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put " ,&var="@; put " ,&var="@;
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
@@ -128,7 +142,7 @@ data _null_;
%end; %end;
%end; %end;
%if &vtype=N %then %do; %if &vtype=N %then %do;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put &var; put &var;
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;
@@ -141,7 +155,7 @@ data _null_;
put _____str; put _____str;
%end; %end;
%end; %end;
%if &flavour=BASE %then %do; %if &flavour=SAS %then %do;
put ';'; put ';';
%end; %end;
%else %if &flavour=PGSQL %then %do; %else %if &flavour=PGSQL %then %do;

View File

@@ -5,6 +5,8 @@
to create tables in SAS or a database. The macro can be used at table or to create tables in SAS or a database. The macro can be used at table or
library level. The default behaviour is to create DDL in SAS format. library level. The default behaviour is to create DDL in SAS format.
Note - views are not currently supported.
Usage: Usage:
data test(index=(pk=(x y)/unique /nomiss)); data test(index=(pk=(x y)/unique /nomiss));
@@ -17,6 +19,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mf_existfileref.sas @li mf_existfileref.sas
@li mf_getvarcount.sas
@li mp_getconstraints.sas @li mp_getconstraints.sas
@param lib libref of the library to create DDL for. Should be assigned. @param lib libref of the library to create DDL for. Should be assigned.
@@ -38,8 +41,8 @@
)/*/STORE SOURCE*/; )/*/STORE SOURCE*/;
/* check fileref is assigned */ /* check fileref is assigned */
%if %mf_existfileref(&outref)=0 %then %do; %if %mf_existfileref(&fref)=0 %then %do;
filename &outref temp ; filename &fref temp ;
%end; %end;
%if %length(&libref)=0 %then %let libref=WORK; %if %length(&libref)=0 %then %let libref=WORK;
@@ -49,6 +52,7 @@ proc sql noprint;
create table _data_ as create table _data_ as
select * from dictionary.tables select * from dictionary.tables
where upcase(libname)="%upcase(&libref)" where upcase(libname)="%upcase(&libref)"
and memtype='DATA' /* views not currently supported */
%if %length(&ds)>0 %then %do; %if %length(&ds)>0 %then %do;
and upcase(memname)="%upcase(&ds)" and upcase(memname)="%upcase(&ds)"
%end; %end;
@@ -143,13 +147,15 @@ run;
put "create table &libref..&curds("; put "create table &libref..&curds(";
end; end;
else do; else do;
/* just a placeholder - we filter out views at the top */
put "create view &libref..&curds("; put "create view &libref..&curds(";
end; end;
put " "@@; put " "@@;
end; end;
else put " ,"@@; else put " ,"@@;
if length(format)>1 then fmt=" format="!!cats(format); if length(format)>1 then fmt=" format="!!cats(format);
if length(label)>1 then lab=" label="!!quote(trim(label)); if length(label)>1 then
lab=" label="!!cats("'",tranwrd(label,"'","''"),"'");
if notnull='yes' then notnul=' not null'; if notnull='yes' then notnul=' not null';
if type='char' then typ=cats('char(',length,')'); if type='char' then typ=cats('char(',length,')');
else if length ne 8 then typ='num length='!!left(length); else if length ne 8 then typ='num length='!!left(length);
@@ -221,6 +227,7 @@ run;
put "create table [&schema].[&curds]("; put "create table [&schema].[&curds](";
end; end;
else do; else do;
/* just a placeholder - we filter out views at the top */
put "create view [&schema].[&curds]("; put "create view [&schema].[&curds](";
end; end;
put " "@@; put " "@@;
@@ -304,71 +311,81 @@ run;
put "CREATE SCHEMA &schema;"; put "CREATE SCHEMA &schema;";
%do x=1 %to %sysfunc(countw(&dsnlist)); %do x=1 %to %sysfunc(countw(&dsnlist));
%let curds=%scan(&dsnlist,&x); %let curds=%scan(&dsnlist,&x);
data _null_; %local curdsvarcount;
file &fref mod; %let curdsvarcount=%mf_getvarcount(&libref..&curds);
put "/* Postgres Flavour DDL for &schema..&curds */"; %if &curdsvarcount>1600 %then %do;
data _null_; data _null_;
file &fref mod; file &fref mod;
set &colinfo (where=(upcase(memname)="&curds")) end=last; put "/* &libref..&curds contains &curdsvarcount vars */";
length fmt $32; put "/* Postgres cannot create tables with over 1600 vars */";
if _n_=1 then do; put "/* No DDL will be generated for this table";
if memtype='DATA' then do; run;
put "CREATE TABLE &schema..&curds ("; %end;
%else %do;
data _null_;
file &fref mod;
put "/* Postgres Flavour DDL for &schema..&curds */";
data _null_;
file &fref mod;
set &colinfo (where=(upcase(memname)="&curds")) end=last;
length fmt $32;
if _n_=1 then do;
if memtype='DATA' then do;
put "CREATE TABLE &schema..&curds (";
end;
else do;
/* just a placeholder - we filter out views at the top */
put "CREATE VIEW &schema..&curds (";
end;
put " "@@;
end; end;
else do; else put " ,"@@;
put "CREATE VIEW &schema..&curds ("; format=upcase(format);
end; if 1=0 then; /* dummy if */
put " "@@; %if &applydttm=YES %then %do;
end; else if format=:'DATETIME' then fmt=' TIMESTAMP ';
else put " ,"@@; %end;
format=upcase(format); else if type='num' then fmt=' DOUBLE PRECISION';
if 1=0 then; /* dummy if */ else fmt='VARCHAR('!!cats(length)!!')';
%if &applydttm=YES %then %do; if notnull='yes' then notnul=' NOT NULL';
else if format=:'DATETIME' then fmt=' TIMESTAMP '; /* quote column names in case they represent reserved words */
%end; name2=quote(trim(name));
else if type='num' then fmt=' DOUBLE PRECISION'; put name2 fmt notnul;
else fmt='VARCHAR('!!cats(length)!!')'; run;
if notnull='yes' then notnul=' NOT NULL';
/* quote column names in case they represent reserved words */
name2=quote(trim(name));
put name2 fmt notnul;
run;
/* Extra step for data constraints */ /* Extra step for data constraints */
%addConst() %addConst()
data _null_; data _null_;
file &fref mod; file &fref mod;
put ');'; put ');';
run; run;
/* Create Unique Indexes, but only if they were not already defined within /* Create Unique Indexes, but only if they were not already defined within
the Constraints section. */ the Constraints section. */
data _null_; data _null_;
*length ds $128; *length ds $128;
set &idxinfo( set &idxinfo(
where=( where=(
memname="&curds" memname="&curds"
and unique='yes' and unique='yes'
and indxname not in ( and indxname not in (
%sysfunc(tranwrd("&constraints_used",%str( ),%str(","))) %sysfunc(tranwrd("&constraints_used",%str( ),%str(",")))
)
) )
) );
); file &fref mod;
file &fref mod; by idxusage indxname;
by idxusage indxname; if first.indxname then do;
/* ds=cats(libname,'.',memname); */
if first.indxname then do;
put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds("; put 'CREATE UNIQUE INDEX "' indxname +(-1) '" ' "ON &schema..&curds(";
put ' "' name +(-1) '"' ; put ' "' name +(-1) '"' ;
end; end;
else put ' ,"' name +(-1) '"'; else put ' ,"' name +(-1) '"';
*else put ' ,' name ; if last.indxname then do;
if last.indxname then do; put ');';
put ');'; end;
end; run;
run; %end;
%end; %end;
%end; %end;
%if %upcase(&showlog)=YES %then %do; %if %upcase(&showlog)=YES %then %do;

View File

@@ -20,8 +20,7 @@
@li mf_getvartype.sas @li mf_getvartype.sas
@param [in] libds dataset to hash @param [in] libds dataset to hash
@param [in] salt= Provide a salt (could be, for instance, the name of the @param [in] salt= Provide a salt (could be, for instance, the dataset name)
dataset). Max 32 chars.
@param [out] outds= (work.mf_hashdataset) The output dataset to create. This @param [out] outds= (work.mf_hashdataset) The output dataset to create. This
will contain one column (hashkey) with one observation (a hex32. will contain one column (hashkey) with one observation (a hex32.
representation of the input hash) representation of the input hash)
@@ -56,7 +55,7 @@
%let varlist=%mf_getvarlist(&libds); %let varlist=%mf_getvarlist(&libds);
data &outds(rename=(&keyvar=hashkey) keep=&keyvar); data &outds(rename=(&keyvar=hashkey) keep=&keyvar);
length &prevkeyvar &keyvar $32; length &prevkeyvar &keyvar $32;
retain &prevkeyvar "&salt"; retain &prevkeyvar "%sysfunc(md5(%str(&salt)),$hex32.)";
set &libds end=&lastvar; set &libds end=&lastvar;
/* hash should include previous row */ /* hash should include previous row */
&keyvar=put(md5(&prevkeyvar &keyvar=put(md5(&prevkeyvar

73
base/mp_lib2inserts.sas Normal file
View File

@@ -0,0 +1,73 @@
/**
@file
@brief Convert all data in a library to SQL insert statements
@details Gets list of members then calls the <code>%mp_ds2inserts()</code>
macro.
Usage:
%mp_getddl(sashelp, schema=work, fref=tempref)
%mp_lib2inserts(sashelp, schema=work, outref=tempref)
%inc tempref;
The output will be one file in the outref fileref.
<h4> SAS Macros </h4>
@li mp_ds2inserts.sas
@param [in] lib Library in which to convert all datasets to inserts
@param [in] flavour= (SAS) The SQL flavour to be applied to the output. Valid
options:
@li SAS (default) - suitable for regular proc sql
@li PGSQL - Used for Postgres databases
@param [in] maxobs= (max) The max number of observations (per table) to create
@param [out] outref= Output fileref in which to create the insert statements.
If it exists, it will be appended to, otherwise it will be created.
@param [out] schema= (0) The schema of the target database, or the libref.
@version 9.2
@author Allan Bowe
**/
%macro mp_lib2inserts(lib
,flavour=SAS
,outref=0
,schema=0
,maxobs=max
)/*/STORE SOURCE*/;
/* Find the tables */
%local x ds memlist;
proc sql noprint;
select distinct lowcase(memname)
into: memlist
separated by ' '
from dictionary.tables
where upcase(libname)="%upcase(&lib)"
and memtype='DATA'; /* exclude views */
%let flavour=%upcase(&flavour);
%if &flavour ne SAS and &flavour ne PGSQL %then %do;
%put %str(WAR)NING: &flavour is not supported;
%return;
%end;
/* create the inserts */
%do x=1 %to %sysfunc(countw(&memlist));
%let ds=%scan(&memlist,&x);
%mp_ds2inserts(&lib..&ds
,outref=&outref
,schema=&schema
,outds=&ds
,flavour=&flavour
,maxobs=&maxobs
)
%end;
%mend mp_lib2inserts;

View File

@@ -13,7 +13,7 @@
* Cars is a great dataset - it contains leading spaces, and formatted numerics * Cars is a great dataset - it contains leading spaces, and formatted numerics
*/ */
%mp_ds2inserts(sashelp.cars,outref=testref,outlib=work,outds=test) %mp_ds2inserts(sashelp.cars,outref=testref,schema=work,outds=test)
data work.test; data work.test;
set sashelp.cars; set sashelp.cars;

View File

@@ -0,0 +1,23 @@
/**
@file
@brief Testing mp_getddl.sas macro
<h4> SAS Macros </h4>
@li mp_getddl.sas
@li mp_assert.sas
**/
data test(index=(pk=(x y)/unique /nomiss));
x=1;
y='blah';
label x='blah';
run;
proc sql; describe table &syslast;
%mp_getddl(work,test,flavour=tsql,showlog=YES)
%mp_assert(
iftrue=(&syscc=0),
desc=mp_getddl runs without errors,
outds=work.test_results
)

View File

@@ -0,0 +1,42 @@
/**
@file
@brief Testing mp_ds2inserts.sas macro
<h4> SAS Macros </h4>
@li mf_mkdir.sas
@li mp_getddl.sas
@li mp_lib2inserts.sas
@li mp_assert.sas
**/
/* grab 20 datasets from SASHELP */
%let path=%sysfunc(pathname(work));
%mf_mkdir(&path)
libname sashlp "&path";
proc sql noprint;
create table members as
select distinct lowcase(memname) as memname
from dictionary.tables
where upcase(libname)="SASHELP"
and memtype='DATA'; /* exclude views */
data _null_;
set work.members;
call execute(cats('data sashlp.',memname,';set sashelp.',memname,';run;'));
if _n_>20 then stop;
run;
/* export DDL and inserts */
%mp_getddl(sashlp, schema=work, fref=tempref)
%mp_lib2inserts(sashlp, schema=work, outref=tempref,maxobs=50)
/* check if it actually runs */
options source2;
%inc tempref;
/* without errors.. */
%mp_assert(
iftrue=(&syscc=0),
desc=Able to export 20 tables from sashelp using mp_lib2inserts,
outds=work.test_results
)