Reputation: 6020
I have very little experience in SAS. I do have experience in SQL.
I want to do the following: - Use a SQL statement that is stored in a text file to import data into SAS.
What works is to copy and paste the SQL server query and run it as a pass-through query in SAS. I get the data (after a few minutes).
But I would like to be able to manage and develop the SQL script in SSMS, and store the script in a sql file. So I tried the following:
proc sql;
connect to ODBC("dsn=DatabaseOfInterest");
create table NewDataSet as select * from connection to odbc(
%include 'C:\sqlscript.sql';
);
quit ;
This does not work and creates the following error:
**ERROR: CLI prepare error:
[Microsoft][ODBC SQL Server Driver][SQL Server]Incorrect syntax near '%'.
**
Is there a way to achieve this?
Upvotes: 3
Views: 4382
Reputation: 101
The original question was about the following code not working in SAS:
proc sql;
connect to ODBC("dsn=DatabaseOfInterest");
create table NewDataSet as select * from connection to odbc(
%include 'C:\sqlscript.sql';
);
quit ;
This is because %include is a GLOBAL statement in SAS. Global statements cannot be used within other statements. Also, semicolons are not allowed in the SQL portion of this code.
An alternative solution would be using %embed() macro that "injects"/inserts lines of code from external file. This macro is described in detail in Embedding any code anywhere into SAS programs.
Using %embed() macro a working version of the code will look like this:
proc sql;
connect to ODBC("dsn=DatabaseOfInterest");
create table NewDataSet as select * from connection to odbc(
%embed(C:\sqlscript.sql)
);
quit ;
Upvotes: 0
Reputation: 8513
Based on feedback from my previous answer I've provided an alternate approach below that should better address your exact needs.
The code below shows how the final program will 'work' once it is all combined together. We are going to take this code and split it into different files as indicated by the comments:
%macro myQuery; /* FILE 1 - header.sas */
select * from myTable; /* FILE 2 - query.sql */
%mend; /* FILE 3 - footer.sas */
/* BEGIN FILE 4 - main.sas */
proc sql;
connect to ODBC("dsn=DatabaseOfInterest");
create table NewDataSet as
select *
from connection to odbc
(
%myQuery;
);
quit ;
/* END FILE 4 */
FILE1 - "header.sas" will look like:
%macro myQuery;
FILE2 - "query.sql" will look like:
select * from myTable;
FILE3 - "footer.sas" will look like:
%mend;
FILE4 will become:
%include "c:\header.sas"
"c:\query.sql"
"c:\footer.sas"
;
proc sql;
connect to ODBC("dsn=DatabaseOfInterest");
create table NewDataSet as
select *
from connection to odbc
(
%myQuery;
);
quit ;
You can see that we are defining the macro using the include statements. The query which is the body of the macro will be kept separate in it's own .sql file. This should allow you to continue to edit/submit your queries via both SAS and your favorite SQL editor. The header and footer files can be re-used if you have multiple query files.
Upvotes: 0
Reputation: 8513
The file containing your SQL code is C:\sqlscript.sql
. I'll assume it looks something like this:
select * from mytable;
Edit the file so that it now looks like this...
%macro sqlscript;
select * from mytable;
%mend;
... and then rename the file extension to C:\sqlscript.sas
.
Finally, change your proc sql
code to look like this:
options sasautos = ("c:\", sasautos);
proc sql;
connect to ODBC("dsn=DatabaseOfInterest");
create table NewDataSet as select * from connection to odbc
(
%sqlscript;
);
quit;
Explanation: The %include
statement you tried to use although it uses a % sign and looks like macro code can't really be substituted in any random point in code as it is a SAS statement. It's really meant to be issued outside of PROC
statements and data steps (it probably shouldn't even have a %sign infront of it but unforunately that's how SAS designed it...). So that's why it won't work.
SAS provides the ability to search for macro functions outside of the current program being run. If you call a macro function that isn't defined in your current SAS program (in this case %sqlscript), it's going to go look for it in the list of pathnames specified in the SASAUTOS option. If it finds a file in one of the SASAUTOS pathnames that exactly matches the macro it's searching for, and if the contents of that file contain a definition for the macro, SAS will compile and run that macro. In the above example, the macro simply substitutes in the SQL code contained within it.
In the options sasautos=
statement - we are simply prepending the c:\
path to the existing list of pathnames currently in SASAUTOS
. It will search the pathnames in order, and I'm assuming we want our custom macros to override any existing macros if there happens to be a conflict. You only need to specifyt options sasautos=
once per SAS session, so don't copy/paste it before every proc sql
statement.
Documentation for SASAUTOS . These are also known as autocall
macros so that should turn up some useful hits in google too.
Also - obviously I don't recommend storing code in c:\
so adjust as necessary. A note to non-windows users - macro names and definitions are case sensitive so be consistent!
Upvotes: 1
Reputation: 63424
I don't know if there's a truly clean way to work around this. The issue is that the connect to SQL is passing %include
to the SQL parser, which is of course incorrect compared to what you intend.
It will, however, correctly resolve macros and macro variables, so you can read your SQL command into a macro variable and use it that way. One way to do that is below.
filename tempfile temp; *imaginary file - this would be your SQL script;
data _null_; *creating a mocked up SQL script file;
file tempfile;
put "select * from country";
run;
data _null_; *reading the SQL script into a variable, hopefully under 32767?;
infile tempfile recfm=f lrecl=32767 pad;
input @1 sqlcode $32767.;
call symputx('sqlcode',sqlcode); *putting it into a macro variable;
run;
proc sql; *using it;
connect to oledb(init_string=&dev_string);
select * from connection to oledb(
&sqlcode.
);
quit;
Upvotes: 3