SAS VBA connection - vba

I tried to run a SAS code through VBA. I'm running SAS on a server. I have a test SAS program "Program1.sas" which I've kept on the server. Below is the VBA code that I've used. The SAS code is running but the output dataset is just showing the column headers and the rows are empty.Can anyone help me what could be the possible reason.
Sub Form_Load23()
Dim obObjectFactory As New SASObjectManager.ObjectFactory
Dim obObjectKeeper As New SASObjectManager.ObjectKeeper
Dim obServer As New SASObjectManager.ServerDef
Dim obSAS As SAS.Workspace
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
obServer.MachineDNSName = "xyz"
obServer.Protocol = SASObjectManager.Protocols.ProtocolBridge
obServer.Port = 8871
obObjectFactory.LogEnabled = True
Set obSAS = obObjectFactory.CreateObjectByServer("sas", True, obServer,"userid", "password")
obSAS.LanguageService.Submit ("options source2; %include '/abc/AFP/shikhar.gupta1/amg/**Program1.sas**';")
End Sub'

I believe you have to change the security settings in excel. Find the security settings and protected viewing. The remove all the check marks.

This is an issue on the SAS side. It can happen when your user does not have the metadata 'read' permission on the relevant dataset. It can also happen if your program has an error, and options obs=0; is set.
As #vasilij mentions, use proc printto to write your log to a file system and check for issues, also use SMC to check your metadata permissions.

Related

VBA is unable to create a connection to a remote SQL Database

I've created an excel front end interface to connect with and manipulate an SQL database. I recently received a laptop, and would like to be able to manipulate the data from excel on said laptop. I established a connection using SQL Server Management Studios to the database.
I've tried to update my excel file; however, the VBA code can not connect to the SQL database. I've changed a few of the variables around and set Integrated Security too, but nothing has worked so far. The error message readouts can be seen here:
Here is the code related to the DB connection:
Dim cnSQL As ADODB.Connection
Set cnSQL = New ADODB.Connection
cnSQL.Open "Provider = SQLOLEDB; Integrated Security = SSPI, Data Source = IP Address,Static TP Port; UID = username; PWD =pwd#; Initial Catalog = database"
The error message highlights the second line of code. I'm hoping to be able to connect to the DB from my laptop.
After struggling for a few days, I finally got this to work. There are two important steps you need to take to make excel work with a Remote SQL network. First here is the code used to connect:
Dim cnSQL As ADODB.Connection
Dim ServerName As String
Dim DatabaseName As String
Dim userID As String
Dim password As String
ServerName = "IP Addresss,Port"
DatabaseName = "DB Name"
userID = "username"
password = "pwd"
Set cnSQL = New ADODB.Connection
sqlCommand.ActiveConnection = cnSQL
After I changed the code to this, I got a new error: "optional feature not implemented." To fix this error, I changed the data type of all 'adDate' to 'adDBTimeStamp.' This works for some reason, I don't know why. It works.

SQLite database file can't be opened when placed in network folder

Can someone help me to understand why this works fine...
Dim cs = "Data Source=C:\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.Open() ' no exception
... while this breaks when opening connection (it is exactly the same file)...
Dim cs = "Data Source=\\NetworkServer\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.Open() ' exception: {"unable to open database file"}
... and fix it because I need to place database file in network location so I can access it regardless of the computer I run the application?
Thank you very much!
Ok, so by trial and error I found the solution, although I can't quite understand the reason it works:
Dim cs = "Data Source=\\NetworkServer\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.ParseViaFramework = True ' JUST ADDED THIS STATEMENT
cn.Open() ' no exception
If somebody can explain why .ParseViaFramework = True does the trick, please feel free to comment.
Similar question was asked here.
SQLite: Cannot open network file programmatically, even though worked before
The top answer gives a few more fixes. Linking here as this is the first stackoverflow that came up when I searched. Also I was using a SQLiteConnectionStringBuilder and could not find a way to set the parseViaFramework so the first solution was the one I needed.
Double the leading two backslashes in the file name (e.g. "\\\\network\share\file.db").
Use a mapped drive letter.
Use the SQLiteConnection constructor that takes the parseViaFramework boolean argument and pass 'true' for that argument.

Changing Connection String VBA

I found this in another answer
Sub UpdateQueryConnectionString(ConnectionString As String)
Dim cn As WorkbookConnection
Dim oledbCn As OLEDBConnection
Set cn = ThisWorkbook.Connections("database")
Set oledbCn = cn.OLEDBConnection
oledbCn.Connection = ConnectionString
End Sub
I seem to be getting an error on Set oledbCn = cn.OLEDBConnection
Run time error 1004
I can output my current connection string like so
MsgBox ThisWorkbook.Connections("database").ODBCConnection.Connection
but trying to assign it gives me the same runtime error 1004
ThisWorkbook.Connections("ID").ODBCConnection.Connection = "anything"
I am sure there is an easy way to simply change the connection string...
Note I created this using the connection wizard to connect to another workbook on my computer the connection type is Database Query. I am using Excel 2013, maybe this is a glitch in Excel 2013...
This is a very common problem. What you need to do is append ODBC; to the beginning of your connection string otherwise it will give you a run time error.

Creating a workspace session using SAS IOM & VBA

I am trying to connect to a workspace server using Excel VBA. Using the information on this page, I have produced the following:
Dim obSAS As SAS.Workspace
Dim obWorkspaceManager As New SASWorkspaceManager.WorkspaceManager
Private Sub Form_Load()
Dim obConnection As New ADODB.Connection
Dim obRecordSet As New ADODB.Recordset
Dim obServerDef As New SASWorkspaceManager.ServerDef
Dim xmlString As String
obServerDef.Port = 28561
obServerDef.Protocol = ProtocolBridge
obServerDef.MachineDNSName = "blah.server.com"
Set obSAS = obWorkspaceManager.Workspaces.CreateWorkspaceByServer( "Ref", _
VisibilityProcess, obServerDef, "me#saspw","MyPass", xmlStr)
end sub
My first response was this:
<xml id="combridgeOutput"><connectionAttempts><connectionAttempt>
<sasserver></sasserver>
<sasmachinednsname>blah.server.com</sasmachinednsname>
<sasport>28561</sasport>
<saslogin>me#saspw</saslogin>
<status>0x80041001</status>
<description><Exceptions><Exception>
<SASMessage severity="Error">
The client has connected to a SAS (9.2) Metadata Server (v1.0) when
it intended to connect to a SAS Workspace Server.
</SASMessage>
</Exception></Exceptions></description>
</connectionAttempt></connectionAttempts></xml>
So I updated the port number to point at the workspace server, and now I get this:
<same XML tags as above >
<SASMessage severity="Error">
Client me#saspw does not have permission to use server
SASMeta - Workspace Server (A5DPDN69.AV000069).
</SASMessage>
Would rather not set special permissions for this exercise. How else can one connect VBA to a SAS workspace server session?
Doh! I was using the wrong machine name. For reference, here is the process for getting the correct machine name!
Log into SMC
Expand Server Manager
Expand SASApp
Expand SASApp - Logical Workspace Server
There you will see the correct machine, and will also show the port details..

Query Tables (QueryTables) in Excel 2010 with VBA with VBA creating many connections

I'm following code I found on another site. Here's the basics of my code:
Dim SQL As String
Dim connString As String
connString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
SQL = "Select * from SomeTable"
With Worksheets("Received").QueryTables.Add(Connection:=connString, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL)
.Refresh
End With
End Sub
The problem with doing this is every single time they hit the button assigned to this it creates a new connection and doesn't ever seem to drop it. I open the spreadsheet after testing and there are many versions of the connection listed under Connections.
Connection
Connection1
Connection2
I can't seem to find a way to close or delete the connections either. If I add ".delete" after ".Refresh" I get a 1004 error. This operation cannot be done because the data is refreshing in the background.
Any ideas how to close or delete the connection?
You might ask yourself why you're creating a QueryTable every time in your code. There are reasons to do it, but it usually isn't necessary.
QueryTables are more typically design-time objects. That is, you create your QueryTable once (through code or the UI) and the you Refresh the QueryTable to get updated data.
If you need to change the underlying SQL statement, you have some options. You could set up Parameters that prompt for a value or get it from a cell. Another option for changing the SQL is changing it in code for the existing QueryTable.
Sheet1.QueryTables(1).CommandText = "Select * FROM ...."
Sheet1.QueryTables(1).Refresh
You can select different columns or even different tables by changing CommandText. If it's a different database, you'll need a new connection, but that's pretty rare.
I know that doesn't answer your question directly, but I think determining whether you really need to add the QueryTable each time is the first step.
For more on Parameters, see http://dailydoseofexcel.com/archives/2004/12/13/parameters-in-excel-external-data-queries/ It's for 2003, so there are few inconsistencies with later versions. The basics are the same, you just may need to learn about the ListObject object if you're using 2007 or later.
I had the same issue. The previous answer while a definite step in the right direction is a PITA.
It did however allow me to refine my search and the winner is...
http://msdn.microsoft.com/en-us/library/bb213491(v=office.12).aspx
i.e. for your existing QueryTable Object just do this:
.MaintainConnection = False
Works ever so swell. No more Access DB lock file after the data is refreshed.
You should declare the connection as a separate object then you can close it once the database query is complete.
I don't have the VBA IDE in front of me, so excuse me if there are any inaccuracies, but it should point you in the right direction.
E.g.
Dim SQL As String
Dim con As connection
Set con = New connection
con.ConnectionString = "ODBC;DSN=DB01;UID=;PWD=;Database=MyDatabase"
Worksheets("Received").QueryTables.Add(Connection:=con, Destination:=Worksheets("Received").Range("A5"), SQL:=SQL).Refresh
con.close
set con = nothing
I've found that by default new connections created this way are called "Connection". What I am using is this snippet of code to remove the connection but retain the listobject.
Application.DisplayAlerts = False
ActiveWorkbook.Connections("Connection").Delete
Application.DisplayAlerts = True
It can easily be modified to remove the latest added connection (or if you keep track of the connections by their index).
Application.DisplayAlerts = False
ActiveWorkbook.Connections(ActiveWorkbook.Connections.Count).Delete
Application.DisplayAlerts = True
Instead of adding another query table with the add method, you can simply update the CommandText Property of the connection. However you have to be aware that there is a bug when updating the CommandText property of an ODBC connection. If you temporarily switch to an OLEDB connection, update your CommandText property and then switch back to ODBC it does not create the new connection. Don't ask me why... this just works for me.
Create a new module and insert the following code:
Option Explicit
Sub UpdateWorkbookConnection(WorkbookConnectionObject As WorkbookConnection, Optional ByVal CommandText As String = "", Optional ByVal ConnectionString As String = "")
With WorkbookConnectionObject
If .Type = xlConnectionTypeODBC Then
If CommandText = "" Then CommandText = .ODBCConnection.CommandText
If ConnectionString = "" Then ConnectionString = .ODBCConnection.Connection
.ODBCConnection.Connection = Replace(.ODBCConnection.Connection, "ODBC;", "OLEDB;", 1, 1, vbTextCompare)
ElseIf .Type = xlConnectionTypeOLEDB Then
If CommandText = "" Then CommandText = .OLEDBConnection.CommandText
If ConnectionString = "" Then ConnectionString = .OLEDBConnection.Connection
Else
MsgBox "Invalid connection object sent to UpdateWorkbookConnection function!", vbCritical, "Update Error"
Exit Sub
End If
If StrComp(.OLEDBConnection.CommandText, CommandText, vbTextCompare) <> 0 Then
.OLEDBConnection.CommandText = CommandText
End If
If StrComp(.OLEDBConnection.Connection, ConnectionString, vbTextCompare) <> 0 Then
.OLEDBConnection.Connection = ConnectionString
End If
.Refresh
End With
End Sub
This UpdateWorkbookConnection subroutine only works on updating OLEDB or ODBC connections. The connection does not necessarily have to be linked to a pivot table. It also fixes another problem and allows you to update the connection even if there are multiple pivot tables based on the same connection.
To initiate the update just call the function with the connection object and command text parameters like this:
UpdateWorkbookConnection ActiveWorkbook.Connections("Connection"), "exec sp_MyAwesomeProcedure"
You can optionally update the connection string as well.
If you want to delete if right after refresh you should do the refresh not in the background (using first parameter -> Refresh False) so that you have proper sequence of actions
Try setting the QueryTable.MaintainConnection property to False...
"Set MaintainConnection to True if the connection to the specified data source is to be maintained after the refresh and until the workbook is closed. The default value is True! And there doesn't seem to be a UI check box for this (Read/write Boolean)"
Still relevant years later...battling the same issue and this is the most helpful thread out there. My situation is a variant of the above and I will add my solution when I find it.
I am using an Access database for my data source and establish a querytable on a new sheet. I then add two more new sheets and try to establish a querytable using the same connection on each of them, but to a different Access table. The first querytable works just fine and I use .QueryTables(1).Delete and setting the querytable object to Nothing to make it disconnected.
However, the next sheet fails on establishing a new querytable using the same connection, which was not closed. I suspect (and will add the solution below) that I need to drop the connection before deleting the querytable. Rasmus' code above looks like the likely solution.