I have never tried to connect to SQL Server before (and not that great at coding).
I tried to read some stuff on the internet - this is how far I am:
I have made a connection in the ODBC Data Source Administration and the test was successfull and i called the database: fpt
Snapshot :
Afterwards I started a program in SAS EG and coded (I use windows SQL authentication, so cahnged username and password to X) :
LIBNAME test ODBC DSN=fpt user=X pw=X
in the log i get the following error and cannot figure out why?
1 ;*';*";*/;quit;run;
2 OPTIONS PAGENO=MIN;
3 %LET _CLIENTTASKLABEL='Program (6)';
4 %LET _CLIENTPROJECTPATH='C:\Users\g46973\Desktop\test.egp';
5 %LET _CLIENTPROJECTNAME='test.egp';
6 %LET _SASPROGRAMFILE=;
7
8 ODS _ALL_ CLOSE;
9 OPTIONS DEV=ACTIVEX;
10 GOPTIONS XPIXELS=0 YPIXELS=0;
11 FILENAME EGSR TEMP;
12 ODS tagsets.sasreport13(ID=EGSR) FILE=EGSR
13 STYLE=HtmlBlue
14 STYLESHEET=(URL="file:///C:/Program%20Files/SASHOME/SASEnterpriseGuide/7.1/Styles/HtmlBlue.css")
15 NOGTITLE
16 NOGFOOTNOTE
17 GPATH=&sasworklocation
18 ENCODING=UTF8
19 options(rolap="on")
20 ;
NOTE: Writing TAGSETS.SASREPORT13(EGSR) Body file: EGSR
21
22 GOPTIONS ACCESSIBLE;
23 LIBNAME test ODBC DSN=fpt user=fptreader pw=XXXXXXXX
24
25 GOPTIONS NOACCESSIBLE;
________
22
ERROR: Libref TEST is not assigned.
ERROR: Error in the LIBNAME statement.
ERROR 22-7: Invalid option name GOPTIONS.
26 %LET _CLIENTTASKLABEL=;
27 %LET _CLIENTPROJECTPATH=;
28 %LET _CLIENTPROJECTNAME=;
29 %LET _SASPROGRAMFILE=;
30
31 ;*';*";*/;quit;run;
32 ODS _ALL_ CLOSE;
33
34
35 QUIT; RUN;
36
Any awesome programmer who can help?
You are missing a semicolon at the end of the libname statement. This causes SAS to think the goptions statement (which is added by EG) is part of the libname statement.
I don't see a DSN switch for the LIBNAME statement.
I think you need DATASRC instead.
Source
Related
When moving data (a char(18) field) from one MSSQL13 to another MSSQL13 I lose "hidden" unicode characters.
Src is Danish_Norwegian_CI_AS.
Tgt is SQL_Latin1_General_CP1_CI_AS.
Example:
The char(18) filed L_KEY in the source table is shown as '9060001429 00099' when I choose "Results to Text".
When I choose "Results to Grid" it is shown as '9060001429'
When I look at the concrete example and its individual characters and their unicode number, I get this:
Pos UnicodeChar UnicodeValue
--- ----------- ------------
1 9 57
2 0 48
3 6 54
4 0 48
5 0 48
6 0 48
7 1 49
8 4 52
9 2 50
10 9 57
11 0
12 0
13 0
14 0 48
15 0 48
16 0 48
17 9 57
18 9 57
So it seems positions 11,12, and 13 hold a null value.
When I select data into a table on the same server with the same collation; I get the same results.
When I select data into a table on a different server with SQL_Latin1_General_CP1_CI_AS I lose positions 11-18 in the above example.
I've tried to create a table in the target database with a column with the same collation as the source column and tried to move data using SSIS import/export wizard.
If I use an explicit conversion in my query in SSIS import/export wizrad
( convert(nvarchar(18),L_KEY) ) I can see the "missing" characters in the SSIS preview window. Nevertheless, when data is inserted into the target table, the characters are gone.
Please help
NB. I cannot use openrowset or linked servers.
I am trying to transpose a sequence of ranges from an excel file into SAS. The excel file looks something like this:
31 Dec 01Jan 02Jan 03Jan 04Jan
Book id1 23 24 35 43 98
Book id2 3 4 5 4 1
(few blank rows in between)
05Jan 06Jan 07Jan 08Jan 09Jan
Book id1 14 100 30 23 58
Book id2 2 7 3 8 6
(and it repeats..)
My final output should have a first column for the date and then two additional columns for the book Ids:
Date Book id1 Book id2
31 Dec 23 3
01Jan 24 4
02Jan 35 5
03Jan 43 4
04Jan 98 1
05Jan 14 2
06Jan 100 7
07Jan 30 3
08Jan 23 8
09Jan 58 6
In this particular case I am asking for a simpler method to:
Either import and transpose each range of data and replacing the data range with macro variables to separately import and transpose each individual range
Or to import the whole datafile first and then to create a loop that
transposes each range of data
Code I used for a simple import and transpose of a specific data range:
proc import datafile="&input./have.xlsx"
out=want
dbms=xlsx replace;
range="Data$A3:F5" ;
run;
proc transpose data=want
out=want_transposed
name=date;
id A;
run;
Thanks!
A data row that is split over several segments or blocks of rows in an Excel file can be imported raw into SAS and then processed into a categorical form using a DATA Step.
In this example sample data is put into a text file and imported such that the column names are generic VAR-1 ... VAR-n. The generic import is then processed across each row, outputting one SAS data set row per import cell.
The column names in each segment are retained within a temporary array an updated whenever a blank book id is encountered.
* mock data;
filename demo "%sysfunc(pathname(WORK))\demo.txt";
data _null_;
input;
file demo;
put _infile_;
datalines;
., 31Dec, 01Jan, 02Jan, 03Jan, 04Jan
Book_id1, 23 , 24 , 35 , 43 , 98
Book_id2, 3 , 4 , 5 , 4 , 1
., 05Jan, 06Jan, 07Jan, 08Jan, 09Jan
Book_id1, 14 , 100 , 30 , 23 , 58
Book_id2, 2 , 7 , 3 , 8 , 6
run;
* mock import;
proc import replace out=work.haveraw file=demo dbms=csv;
getnames = no;
datarow = 1;
run;
ods listing;
proc print data=haveraw;
run;
When Excel import is be made to look like this:
Obs VAR1 VAR2 VAR3 VAR4 VAR5 VAR6
1 31Dec 01Jan 02Jan 03Jan 04Jan
2 Book_id1 23 24 35 43 98
3 Book_id2 3 4 5 4 1
4
5 05Jan 06Jan 07Jan 08Jan 09Jan
6 Book_id1 14 100 30 23 58
7 Book_id2 2 7 3 8 6
It can be processed in a transposing way, outputting only the name value pairs corresponding to a original cell.
data have (keep=bookid date value);
set haveraw;
array dates(1000) $12 _temporary_ ;
array vars var:;
if missing(var1) then do;
do index = 2 by 1 while (index <= dim(vars));
if not missing(vars(index)) then
dates(index) = put(index-1,z3.) || '_' || vars(index); * adjust as you see fit;
else
dates(index) = '';
end;
end;
else do;
bookid = var1;
do index = 2 by 1 while (index <= dim(vars));
date = dates(index);
value = input(vars(index),??best12.);
output;
end;
end;
run;
I have a sas-db file on a file server and want to check, if it is opened by another PC.
I tried several attempts using this sources http://www.wuss.org/proceedings11/Papers_Galligan_O_74889.pdf http://support.sas.com/documentation/cdl/en/lefunctionsref/63354/HTML/default/viewer.htm#p0a6vn2td7bjr2n1viy8y4lgvq61.htm with no success.
The numbers(fid) in the log never turn 0, irrespective if the file is open on the other PC or not.
%MACRO Try;
%let filrf=myfile;
%let rc=%sysfunc(filename(filrf,\\inti\[...]\p3001_overviewsampling.sas7bdat));
%let fid=%sysfunc(fopen(&filrf));
%PUT RC is: &RC // fid is &fid ;
%MEND;
%Try;
LOG: RC is: 20036 // fid is 30
Any ideas?
Thanks, Lubenja
------ EDIT after the answer of data null ----------------
Thanks for the repose. However, if I run your macro twice it is not working any more. Somehow the file gets locked even if running from the same PC. And now I cant delete the file any more from whichever PC.
17 %LET Path =\\hugo\Temp;
18 LIBNAME test "&Path";
NOTE: Libref TEST was successfully assigned as follows:
Engine: V9
Physical Name: \\hugo\Temp
19
20
21 data test.class2;
22 set sashelp.class;
23 run;
NOTE: There were 19 observations read from the data set SASHELP.CLASS.
NOTE: The data set TEST.CLASS2 has 19 observations and 5 variables.
NOTE: DATA statement used (Total process time):
real time 0.06 seconds
cpu time 0.01 seconds
24
25 %MACRO Try(data=,library=);
26 %let filrf=myfile;
27 %let rc=%sysfunc(filename(filrf,%sysfunc(pathname(&library))/&data..sas7bdat));
28 %let fid=%sysfunc(fopen(&filrf,O));
29 %PUT RC is: &RC // fid is &fid ;
30 %if &fid %then %let rc=%sysfunc(fclose(&fid));
31 %MEND;
32 %Try(data=class2,library=test);
RC is: 0 // fid is 1
33 %Try(data=class2,library=test);
RC is: 0 // fid is 0
34 data test.class2;
35 set sashelp.class;
36 run;
ERROR: An I/O error has occurred on file TEST.CLASS2.DATA.
NOTE: The SAS System stopped processing this step because of errors.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
I had to add the O output option to FOPEN
25 data class;
26 set sashelp.class;
27 run;
NOTE: There were 19 observations read from the data set SASHELP.CLASS.
NOTE: The data set WORK.CLASS has 19 observations and 5 variables.
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.01 seconds
28 %let did = %sysfunc(open(class));
29 %put &=did;
DID=1
30
31 %MACRO Try(data=);
32 %let filrf=myfile;
33 %let rc=%sysfunc(filename(filrf,%sysfunc(pathname(work))/&data..sas7bdat));
34 %let fid=%sysfunc(fopen(&filrf,O));
35 %PUT RC is: &RC // fid is &fid ;
36 %if &fid %then %let rc=%sysfunc(fclose(&fid));
37 %MEND;
38 %Try(data=class)
Resource is read-locked by another thread. File
=/opt/local/saswork/...redacted.../class.sas7bdat.
RC is: 0 // fid is 0
39
40 %let rc=%sysfunc(close(&did));
41 %put &=rc;
RC=0
The following is an approach to handling this case, although unfortunately it still writes an ERROR to the log:
%let lib=YOURLIB;
%let ds=YOURDS;
/* first - test for syscc>0 and handle */
/* next, attempt to gain update access and set var if successful */
%let locked=yes;
data &lib..&ds;
modify &lib..&ds;
call symputx('locked','no');
stop;
run;
/* if error, or explicity locked, handle the case */
%if &syscc>0 or &locked=yes %then %do;
%let syscc=0;
options obs=max replace nosyntaxcheck;
/* DO SOMETHING HERE */
%end;
I have several variables in data set survey. I want to write a loop to load each variable into a SAS macro.
the code is below.
%let var= r1 r2 r3 ;
DATA survey;
INPUT id sex $ age inc r1 r2 r3 ;
DATALINES;
1 F 35 17 7 2 2
17 M 50 14 5 5 3
33 F 45 6 7 2 7
49 M 24 14 7 5 7
65 F 52 9 4 7 7
81 M 44 11 7 7 7
2 F 34 17 6 5 3
18 M 40 14 7 5 2
34 F 47 6 6 5 6
50 M 35 17 5 7 5
;
%MACRO bvars(input);
proc univariate data = "D:\hsb2" plots;
var &input.;
run;
%MEND bvars;
I just want &var can load into macro bvars each time for only one variable instead of writing the following.
%bvars(r1)
%bvars(r2)
%bvars(r3)
.....
This is time consuming while the number of variables are bigger than 100.
This will run proc univariate for all the variables in survay which start with "r" (so r1, r2, etc.). Procedures with a var statement usually accept multiple variables.
proc univariate data = survey;
var r:;
run;
If you wish to run for all numeric variables replace r: with _NUM_.
If you want to loop through the variables and call a function seperately each time there are several approaches. Usually they involve a macro do loop (which must be inside a macro) like so:
%macro looper(inData);
/* List all the variable names */
proc contents data = &inData. out = _colNames noprint;
run;
proc sql noprint;
select name
/* Put the variable names in a macro variable list */
into :colNames separated by " "
from _colNames
/* Get only numeric variables */
where type = 1
order by varnum;
quit;
/* Loop through the variable names */
%do i = 1 %to %sysfunc(countw(&colNames.));
%let colName = %scan(&colNAmes., &i.);
%put &colName.;
/* Your macro call or code here */
/* %bvars(&inData., &colName.) */
%end;
%mend looper;
%looper(sashelp.cars);
It might prove useful for you to become familiar with macro %do loops, proc contents (or better yet proc datasets), the %scan() function and the different ways to assign macro variables. The sas documentation online is a great place to start.
Updated answer.
You can utilise the VCOLUMN table that is automatically created for every SAS dataset in each library including the Work library. This table contains a row for each variable for each dataset in SAS.
So you would do the following. I am assuming your survery dataset is in the Work library.
So the code does the following;
1. Looks ups your dataset in the Vcolumn table and only keep the name of the variable (thats all we need) and store it into dataset temp.
2. For every variable run the bvars Marcro via the call execute statement.
data temp(keep=name);
set Sashelp.Vcolumn;
where libname = 'WORK' and memname = 'SURVEY';
run;
*Call macro using call execute;
data _null_;
set temp;
call execute ("%bvars("||name||");");
run;
I have something weird...
I am trying to do a proxy DLL for an old game (based on LithTech engine, abandonware, Windows 98 application), so I used wrappit, made the DLL, made it compiling, but... Well...
The DLL itself seems to be OK. At least the DllMain gets executed when testing with LOADDLL from OllyDbg...
But when I insert it into the game folder instead of the original DLL, it loads the DLL, and then it doesn't execute the DLL entry point DllMain! In some builds (Visual Studio 2005) it just says nothing. In other builds (Visual Studio 2010) it raises the c0000139 exception (which is "Entry point not found"). But how can it be that entry point is not found when it loads fine with LOADDLL in ollydbg, which means that the entry oint is in place?
Please help me!
UPD:
Posting the dumpbin /exports output:
The original DLL:
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file IMUSIC25_.DLL
File Type: DLL
Section contains the following exports for IMUSIC25.DLL
00000000 characteristics
33713027 time date stamp Thu May 08 05:45:11 1997
0.00 version
1 ordinal base
29 number of functions
29 number of names
ordinal hint RVA name
6 0 0000FD8B DllCanUnloadNow
7 1 0000FDF9 DllGetClassObject
8 2 0000FD85 DllRegisterServer
9 3 0000FD88 DllUnregisterServer
1 4 000105BD _AllocAAEngine2#8
2 5 00010507 _AllocAAEngine#4
3 6 00007101 _AllocAALoader#4
4 7 000074FC _AllocAALoaderLite#4
5 8 00010675 _AllocAAMIDIIn#4
10 9 000106A1 _GetFinalMIDISink#4
11 A 0001127F _LoadBandFile#12
12 B 000115F9 _LoadMotifFile#12
13 C 00011601 _LoadPatternFile#12
14 D 0001123C _LoadPersonalityByName#12
15 E 000111F9 _LoadPersonalityFile#12
16 F 000118F7 _LoadPersonalityFromMemory#12
17 10 0001131E _LoadSectionFile#12
18 11 000114BB _LoadSongFile#12
19 12 000111B6 _LoadStyleByName#12
20 13 00011173 _LoadStyleFile#12
21 14 0001182C _LoadStyleFromMemory#12
22 15 0001155A _LoadTemplateFile#12
23 16 000102B1 _MusicEngineSimpleInit95#12
24 17 00010497 _MusicEngineSimpleInit#12
25 18 00010066 _MusicEngineSimpleInitNT#12
26 19 000119C2 _Panic#4
27 1A 00011465 _SaveSectionAsMIDIFile#8
28 1B 000113E1 _SaveSectionFile#8
29 1C 00010692 _SetAADebug#4
Summary
4000 .data
1000 .idata
1000 .rdata
2000 .reloc
1000 .rsrc
1B000 .text
My crafted DLL:
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file IMUSIC25.DLL
File Type: DLL
Section contains the following exports for imusic25.dll
00000000 characteristics
52F816DB time date stamp Mon Feb 10 04:01:31 2014
0.00 version
1 ordinal base
30 number of functions
30 number of names
ordinal hint RVA name
6 0 00001020 DllCanUnloadNow = ___E__0__#0
7 1 00001030 DllGetClassObject = ___E__1__#0
8 2 00001040 DllRegisterServer = ___E__2__#0
9 3 00001050 DllUnregisterServer = ___E__3__#0
2 4 00001060 _AllocAAEngine = ___E__5__#0
1 5 00001130 _AllocAAEngine2 = ___E__4__#0
3 6 00001070 _AllocAALoader = ___E__6__#0
4 7 00001080 _AllocAALoaderLite = ___E__7__#0
5 8 00001090 _AllocAAMIDIIn = ___E__8__#0
30 9 00001000 _DllMain#12 = _DllMain#12
10 A 000010A0 _GetFinalMIDISink = ___E__9__#0
11 B 000010B0 _LoadBandFile = ___E__10__#0
12 C 000010C0 _LoadMotifFile = ___E__11__#0
13 D 000010D0 _LoadPatternFile = ___E__12__#0
14 E 000010E0 _LoadPersonalityByName = ___E__13__#0
15 F 000010F0 _LoadPersonalityFile = ___E__14__#0
16 10 00001100 _LoadPersonalityFromMemory = ___E__15__#0
17 11 00001130 _LoadSectionFile = ___E__4__#0
18 12 00001110 _LoadSongFile = ___E__17__#0
19 13 00001120 _LoadStyleByName = ___E__18__#0
20 14 00001130 _LoadStyleFile = ___E__4__#0
21 15 00001150 _LoadStyleFromMemory = ___E__20__#0
22 16 00001160 _LoadTemplateFile = ___E__21__#0
24 17 00001180 _MusicEngineSimpleInit = ___E__23__#0
23 18 00001170 _MusicEngineSimpleInit95 = ___E__22__#0
25 19 00001190 _MusicEngineSimpleInitNT = ___E__24__#0
26 1A 000011A0 _Panic = ___E__25__#0
27 1B 000011B0 _SaveSectionAsMIDIFile = ___E__26__#0
28 1C 000011C0 _SaveSectionFile = ___E__27__#0
29 1D 000011D0 _SetAADebug = ___E__28__#0
Summary
1000 .data
1000 .rdata
1000 .rsrc
1000 .text
UPD: I checked the "GetLastError" on the failing LoadLibraryA call - it is 0x1E7 (487) - ERROR_INVALID_ADDRESS
Well, I managed to fix that by changing the definition of the functions and making them like in the original one.
For that, you need to set the function type to WINAPI (actually it is __stdcall but it seems that the compiler/linker somehow differentiates them? Because the mangling behaviour was different between __stdcall and WINAPI) and define the function parameters - you can calculate the number of needed ones from the last part of the mangled name (which is actually not present in the resulting DLL with the DEF file): #4 means one 4 bytes sized parameter (example - int), #8 means two, etc. You don't even need to know which is exactly the parameter type if you are working with wrappit generated functions - you just need to adjust the size to make mangling correct.
Next, you need to define the relation between the mangled names and ordinals in the DEF file.
There is probably a better and easier approach of using #pragma comment(linker, "/EXPORT:Function=Function#4,#1"), as per C++ DLL Export: Decorated/Mangled names (#wqw's answer) but I haven't tried it.
Also I needed to set up the relocations in project settings - that was probably the cause of "ERROR_INVALID_ADDRESS".
Case closed.