version 2.1

recompiled with new framework setup
This commit is contained in:
yabwon
2020-07-30 14:45:19 +02:00
parent f4493aef1c
commit 6841f6bd08
11 changed files with 402 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
/*** HELP START ***/
/* >>> dsSQL library: <<<
*
* The dsSQL library stores temporary views
* generated during the %SQL() macro execution.
* If possible a subdirectory of WORK is created as:
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))/dsSQLtmp";
* if not possible then redirects to WORK as:
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))";
**/
/*** HELP END ***/
data _null_;
length rc0 $ 32767 rc1 rc2 8;
rc0 = DCREATE("dsSQLtmp", "%sysfunc(pathname(work))/" );
rc1 = LIBNAME("dsSQL", "%sysfunc(pathname(work))/dsSQLtmp", "BASE");
rc2 = LIBREF ("dsSQL" );
if rc2 NE 0 then
rc1 = LIBNAME("dsSQL", "%sysfunc(pathname(work))", "BASE");
run;
/* list details about the library in the log */
libname dsSQL LIST;

View File

@@ -0,0 +1,65 @@
/*** HELP START ***/
/* >>> %dsSQL_Inner() macro: <<<
*
* Internal macro called by dsSQL() function.
* The macro generates a uniqualy named sql view on the fly
* which is stored in DSSQL library.
*
* Recommended for SAS 9.3 and higher.
* Based on paper:
* "Use the Full Power of SAS in Your Function-Style Macros"
* by Mike Rhoads, Westat, Rockville, MD
* https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
*
**/
/*** HELP END ***/
/* inner macro */
%MACRO dsSQL_Inner() / secure;
%local query tempfile1 tempfile2 ps_tmp;
%let query = %superq(query_arg);
%let query = %sysfunc(dequote(&query));
%let viewname = dsSQL.dsSQLtmpview&UNIQUE_INDEX_2.;
%let tempfile1 = A%sysfunc(datetime(), hex7.);
%let tempfile2 = B%sysfunc(datetime(), hex7.);
filename &tempfile1. temp;
filename &tempfile2. temp;
%let ps_tmp = %sysfunc(getoption(ps));
options ps = MAX;
proc printto log = &tempfile1.;
run;
/* get the query shape i.e. the executed one */
proc sql feedback noexec;
&query
;
quit;
proc printto;
run;
options ps = &ps_tmp.;
%put *** executed as ***;
data _null_;
infile &tempfile1. FIRSTOBS = 2; /* <- 2 to ignore header */
file &tempfile2.;
/* create the view name */
if _N_ = 1 then
put " create view &viewname. as ";
input;
put _infile_;
putlog ">" _infile_;
run;
%put *****************;
proc sql;
%include &tempfile2.; /* &query */
;
quit;
filename &tempfile1. clear;
filename &tempfile2. clear;
%MEND dsSQL_Inner;

View File

@@ -0,0 +1,56 @@
/*** HELP START ***/
/* >>> %SQL() macro: <<<
*
* Main macro which allows to use
* SQL's queries in the data step.
* Recommended for SAS 9.3 and higher.
* Based on paper:
* "Use the Full Power of SAS in Your Function-Style Macros"
* by Mike Rhoads, Westat, Rockville, MD
* https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
*
* SYNTAX:
%sql(<nonempty sql querry code>)
* The sql querry code is limited to 32000 bytes.
*
* EXAMPLE 1: simple sql query
data class_subset;
set %SQL(select name, sex, height from sashelp.class where age > 12);
run;
* EXAMPLE 2: query with dataset options
data renamed;
set %SQL(select * from sashelp.class where sex = "F")(rename = (age=age2));
run;
* EXAMPLE 3: dictionaries in datastep
data dictionary;
set %SQL(select * from dictionary.macros);
run;
**/
/*** HELP END ***/
/* Main User macro */
%MACRO SQL() / PARMBUFF SECURE;
%let SYSPBUFF = %superq(SYSPBUFF); /* macroquoting */
%let SYSPBUFF = %substr(&SYSPBUFF, 2, %LENGTH(&SYSPBUFF) - 2); /* remove brackets */
%let SYSPBUFF = %superq(SYSPBUFF); /* macroquoting */
%let SYSPBUFF = %sysfunc(quote(&SYSPBUFF)); /* quotes */
%put NOTE:*** the query ***; /* print out the query in the log */
%put NOTE-&SYSPBUFF.;
%put NOTE-*****************;
%local UNIQUE_INDEX; /* internal variable, a unique index for views */
%let UNIQUE_INDEX = &SYSINDEX;
%sysfunc(dsSQL(&UNIQUE_INDEX, &SYSPBUFF)) /* <-- call dsSQL() function,
see the WORK.SQLinDSfcmp dataset */
%MEND SQL;

View File

@@ -0,0 +1,42 @@
/*** HELP START ***/
/* >>> dsSQL() function: <<<
*
* Internal function called by %SQL() macro.
* The function pass query code from the %SQL()
* macro to the %dsSQL_Inner() innternal macreo.
*
* Recommended for SAS 9.3 and higher.
* Based on paper:
* "Use the Full Power of SAS in Your Function-Style Macros"
* by Mike Rhoads, Westat, Rockville, MD
* https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
*
**/
/*** HELP END ***/
proc fcmp
/*inlib = work.&packageName.fcmp*/
outlib = work.&packageName.fcmp.package
;
function dsSQL(unique_index_2, query $) $ 41;
length
query query_arg $ 32000 /* max query length */
viewname $ 41
;
query_arg = dequote(query);
rc = run_macro('dsSQL_Inner' /* <-- inner macro */
,unique_index_2
,query_arg
,viewname
);
if rc = 0 then return(trim(viewname));
else
do;
put 'ERROR:[function dsSQL] A problem with the dsSQL() function';
return(" ");
end;
endsub;
run;
quit;

View File

@@ -0,0 +1,10 @@
proc sort data=sashelp.class out=test1;
by age name;
run;
data class;
set %SQL(select * from sashelp.class order by age, name);
run;
proc compare base = test1 compare = class;
run;

View File

@@ -0,0 +1,29 @@
data class_work;
set sashelp.class;
run;
data test_work;
set %sql(select * from class_work);
run;
options dlcreatedir;
libname user "%sysfunc(pathname(work))/user";
%put *%sysfunc(pathname(user))*;
data cars_user cars_user2;
set sashelp.cars;
run;
data test_user;
set %sql(select * from cars_user);
run;
data test_user2;
set %sql(select * from user.cars_user2);
run;
libname user clear;
%put *%sysfunc(pathname(user))*;
proc datasets lib = work;
run;

View File

@@ -0,0 +1,45 @@
/* This is the description file for the package. */
/* The colon (:) is a field separator and is restricted */
/* in lines of the header part. */
/* **HEADER** */
Type: Package :/*required, not null, constant value*/
Package: SQLinDS :/*required, not null, up to 24 characters, naming restrictions like for a dataset name! */
Title: SQL queries in Data Step :/*required, not null*/
Version: 2.1 :/*required, not null*/
Author: Mike Rhoads (RhoadsM1@Westat.com) :/*required, not null*/
Maintainer: Bartosz Jablonski (yabwon@gmail.com) :/*required, not null*/
License: MIT :/*required, not null, values: MIT, GPL2, BSD, etc.*/
Encoding: UTF8 :/*required, not null, values: UTF8, WLATIN1, LATIN2, etc. */
Required: "Base SAS Software" :/*optional, COMMA separated, QUOTED list, names of required SAS products, values must be like from proc setinit;run; output */
/* **DESCRIPTION** */
/* All the text below will be used in help */
DESCRIPTION START:
The SQLinDS package is an implementation of
the macro-function-sandwich concept introduced in:
"Use the Full Power of SAS in Your Function-Style Macros"
the article by Mike Rhoads, Westat, Rockville, MD
Copy of the article is available at:
https://support.sas.com/resources/papers/proceedings12/004-2012.pdf
Package provides ability to "execute" SQL queries inside a datastep, e.g.
data class;
set %SQL(select * from sashelp.class);
run;
SQLinDS package contains the following components:
1) %SQL() macro - the main package macro available for the User
2) dsSQL() function (internal)
3) %dsSQL_inner() macro (internal)
4) Library DSSQL (created in a subdirectory of the WORK library)
See help for the %SQL() macro to find more examples.
DESCRIPTION END:

View File

@@ -0,0 +1,25 @@
filename packages "C:\SAS_PACKAGES\SASPackagesFramework";
%include packages(SPFinit.sas);
ods html;
%generatePackage(filesLocation=C:\SAS_PACKAGES_DEV\SQLinDS)
/*
* filename reference "packages" and "package" are keywords;
* the first one should be used to point folder with packages;
* the second is used internally by macros;
filename packages "C:\SAS_PACKAGES";
%include packages(SPFinit.sas);
dm 'log;clear';
%loadpackage(SQLinDS)
%helpPackage(SQLinDS)
%helpPackage(SQLinDS,*)
%unloadPackage(SQLinDS)
*/

View File

@@ -0,0 +1,19 @@
Copyright (c) 2012 Mike Rhoads
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,82 @@
options dlCreateDir;
libname dsSQL "%sysfunc(pathname(work))/dsSQLtmp";
/* makro zewnetrzne */
%MACRO SQL() / PARMBUFF SECURE;
%let SYSPBUFF = %superq(SYSPBUFF); /* maskujemy znaki specjalne */
%let SYSPBUFF = %substr(&SYSPBUFF,2,%LENGTH(&SYSPBUFF) - 2); /* kasujemy otwierający i zamykający nawias */
%let SYSPBUFF = %superq(SYSPBUFF); /* maskujemy jeszcze raz */
%let SYSPBUFF = %sysfunc(quote(&SYSPBUFF)); /* dodajemy cudzyslowy */
%put ***the querry***;
%put &SYSPBUFF.;
%put ****************;
%local UNIQUE_INDEX; /* dodatkowa zmienna indeksujaca, zeby tworzony widok byl unikalny */
%let UNIQUE_INDEX = &SYSINDEX; /* przypisujemy jej wartosc */
%sysfunc(dsSQL(&UNIQUE_INDEX, &SYSPBUFF)) /* <-- wywolulemy funkcje dsSQL */
%MEND SQL;
/* funkcja */
%macro MacroFunctionSandwich_functions();
%local _cmplib_;
options APPEND=(cmplib = WORK.DATASTEPSQLFUNCTIONS) ;
%let _cmplib_ = %sysfunc(getoption(cmplib));
%put NOTE:[&sysmacroname.] *&=_cmplib_*;
options cmplib = _null_;
proc fcmp outlib=work.datastepSQLfunctions.package;
function dsSQL(unique_index_2, query $) $ 41;
length query query_arg $ 32000 viewname $ 41; /* query_arg mozna zmienic na dluzszy, np. 32000 :-) */
query_arg = dequote(query);
rc = run_macro('dsSQL_Inner', unique_index_2, query_arg, viewname); /* <-- wywolulemy makro wewnetrzne dsSQL_Inner */
if rc = 0 then return(trim(viewname));
else do;
return(" ");
put 'ERROR:[function dsSQL] A problem with the function';
end;
endsub;
run;
options cmplib = &_cmplib_.;
%let _cmplib_ = %sysfunc(getoption(cmplib));
%put NOTE:[&sysmacroname.] *&=_cmplib_*;
%mend MacroFunctionSandwich_functions;
%MacroFunctionSandwich_functions()
/* delete macro MacroFunctionSandwich_functions since it is not needed */
proc sql;
create table _%sysfunc(datetime(), hex16.)_ as
select memname, objname
from dictionary.catalogs
where
objname = upcase('MACROFUNCTIONSANDWICH_FUNCTIONS')
and objtype = 'MACRO'
and libname = 'WORK'
order by memname, objname
;
quit;
data _null_;
set _last_;
call execute('proc catalog cat = work.' !! strip(memname) !! ' et = macro force;');
call execute('delete ' !! strip(objname) !! '; run;');
call execute('quit;');
run;
proc delete data = _last_;
run;
/* makro wewnetrzne */
%MACRO dsSQL_Inner() / SECURE;
%local query;
%let query = %superq(query_arg);
%let query = %sysfunc(dequote(&query));
%let viewname = dsSQL.dsSQLtmpview&UNIQUE_INDEX_2;
proc sql;
create view &viewname as &query;
quit;
%MEND dsSQL_Inner;

BIN
packages/sqlinds.zip Normal file

Binary file not shown.