Access VBA generated ODBC connection string reverts - sql-server

I am creating a local MS Access (365) front end application for a SQL Server (Express 2019) DB which is located on a local shared server.
I have a login form that relinks all of the linked tables and views when a user logs in. (This is not primarily for security, so please don't tell me how inadequate this set up is for security - I know.)
Basically, I have a local table in the Access application that lists all the table names that need relinking at login. At login, the current links are deleted, then the code loops through the list of tables and links them according to a connection string that is built in the process, including the UID and the PWD. But when I check on the connection string after login, it doesn't include the login info. My Excel workbook that has a data connection to one of these linked tables cannot connect until I manually edit the string in the Linked Table Manager.
Below is the code for the login process:
Private Sub cmdConnect_Click()
Dim db As Database
Dim tdf As TableDef
Dim rst As Recordset
Dim rst1 As Recordset
Dim strServer As String
Dim strDB As String
Dim strTable As String
Dim strConnect As String
Dim strMsg As String
Dim strPass As String
Dim strPrimary As String
On Error GoTo HandleErr
Set db = CurrentDb
strPass = DLookup("[Password]", "tblUsers", "[User] = '" & Me.txtUser & "'")
If StrComp(Me.txtPwd, strPass, vbBinaryCompare) <> 0 Then
strMsg = "Incorrect Username or password!"
GoTo ExitHere
End If
' Create a recordset to obtain server object names.
Set rst = db.OpenRecordset("tblSQLTables", dbOpenSnapshot)
If rst.EOF Then
strMsg = "There are no tables listed in tblSQLTables."
GoTo ExitHere
End If
'Assign the current user in table
Set rst1 = db.OpenRecordset("tblUsers", dbOpenDynaset, dbSeeChanges)
With rst1
.MoveFirst
Do Until rst1.EOF
.Edit
Select Case !user
Case Me.txtUser
!Current = -1
Case Else
!Current = 0
End Select
.Update
.MoveNext
Loop
End With
strConnect = "ODBC;Driver={ODBC Driver 17 for SQL Server};Trusted_Connection=No;DSN=SQL1;UID=" _
& Me.txtUser & ";PWD=" & Me.txtPwd & ";"
'delete all existing linked tables
Call deleteLinks
' Walk through the recordset and create the links.
Do Until rst.EOF
strServer = rst!SQLServer
strDB = rst!SQLDatabase
strTable = rst!SQLTable
' Create a new TableDef object.
Set tdf = db.CreateTableDef("dbo_" & strTable, 0, "dbo." & strTable, strConnect & "Server=" & strServer & ";Database=" & strDB & ";")
' Set the Connect property to establish the link.
db.TableDefs.Append tdf
Debug.Print tdf.Connect
Set tdf = Nothing
rst.MoveNext
Loop
strMsg = "Tables linked successfully."
rst.Close
Set rst = Nothing
Set tdf = Nothing
Set db = Nothing
DoCmd.Close acForm, Me.name
DoCmd.OpenForm "frmStart"
ExitHere:
MsgBox strMsg, , "Link SQL Tables"
Exit Sub
HandleErr:
Select Case Err
Case Else
strMsg = Err & ": " & Err.Description
Resume ExitHere
End Select
End Sub
Private Sub deleteLinks()
Dim rst As Recordset
Dim db As Database
Dim tdf As TableDef
Set db = CurrentDb
For Each tdf In db.TableDefs
If tdf.name Like "dbo_*" Then
DoCmd.DeleteObject acTable, tdf.name
End If
Next
End Sub
When I look at the immediate window to see the printed tdf.connect it gives me:
ODBC;DRIVER=ODBC Driver 17 for SQL Server;SERVER=RNC1SQL\SQLEXPRESS;UID=****;PWD=*************;Trusted_Connection=No;APP=Microsoft Office;DATABASE=RNCMasterfile;
But when I look at the connection string in the Linked Table Manager, I get the following:
DRIVER=ODBC Driver 17 for SQL Server;SERVER=RNC1SQL\SQLEXPRESS;Trusted_Connection=No;APP=Microsoft Office;DATABASE=RNCMasterfile;
The odd thing is I can access and use the tables in Access, but I have Excel spreadsheets with connections to Access queries based on the linked tables and they don't work if the connection string doesn't contain the login info.
Any ideas to programmatically force the connection string to contain this info?

Try linking your tables using DoCmd.TransferDatabase instead.
DoCmd.TransferDatabase acLink, "ODBC Database", [your_cnn_string], acTable, [source_tbl_name], [linked_table_name], , True
The last option in TranserDatabase is StoreLogin.
I use this in my own apps.
Read about TransferDatabase here.

Related

Creating login procedure for Linking MS Access to Azure SQL server

I have an MS Access program which contains a number of SQL tables which are linked to Azure SQL server. Ideally I would like to create a login procedure via a popup form, in which I would ask the user for credentials where I would then update the linked tables and pass through queries with the required data. However I can't get this to work. The code runs fine without error messages, however when I - after executing the procedure - open a form that contains a linked table, I still get the request to login. The idea is to have the login procedure run at the startup screen, with the user not being asked to enter credentials anywhere after successful login.
This is the code I am using for this:
Public Function ConnectToAzureSQL(sServer As String, sDatabase As String, sUserName As String, sPassWord As String)
On Error GoTo Proc_err
Dim con As Object
Dim var As Variant
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strConnect As String
Set db = CurrentDb
Set con = CreateObject("ADODB.Connection")
strConnect = "DRIVER={ODBC Driver 17 for SQL Server}" & _
";Server=sServer" & _
";Database=sDatabase" & _
";UID=sUserName" & _
"PWD=sPassWord".
con.Open strConnect
For Each tdf In db.TableDefs
Debug.Print tdf.Name
If Len(tdf.Connect) Then
tdf.Connect = strConnect
tdf.RefreshLink
End If
Next
con.Close
Proc_exit:
MsgBox ("done")
Exit Function
Proc_err:
Debug.Print Err.Description & " : " & Str(Err.Number)
Resume Proc_exit
End Function
What I forgot to mention is that this method uses the SQL server login method.
Fortunately, I found the answer myself. Should anyone need it, here is the procedure. The disadvantage of this method is that the login data is captured in the connection string. On second thought, I opted for the Azure Active Directory login method with MFA, where no password is stored in your application.
Public Function ConnectToAzureSQL(sServer, sDb, sUID, sPWD As String, bConn As Boolean)
On Error GoTo Proc_err
Dim con As Object
Dim var As Variant
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strConnect As String
Set db = CurrentDb
Set con = CreateObject("ADODB.Connection")
sConnect = "DRIVER={ODBC Driver 17 for SQL Server}" & _
";Server=" & sServer _
& ";Database=" & sDb _
& ";UID=" & sUID _
& ";PWD=" & sPWD
con.Open strConnect
bConn = True
DoCmd.OpenForm "Frm_Bericht"
For Each tdf In db.TableDefs
If Len(tdf.Connect) Then
tdf.Connect = strConnect & ";UID=" & sUID & ";PWD=" & sPWD
Forms!Frm_Bericht.Caption = "Update verbinding naar tabel: " & tdf.Name
tdf.RefreshLink
End If
Next
con.Close
DoCmd.Close acForm, "Frm_Bericht"
Proc_exit:
Exit Function
Proc_err:
Debug.Print Err.Description & " : " & Str(Err.Number)
Resume Proc_exit
End Function

Adding SQL Server Credentials to ADO Connection

I have an Excel workbook that builds a bunch of SQL Update scripts, and then executes them in SQL Server.
I got assistance with the below VBA script. The below works fine if I am running it while logged in as the Admin user Windows. However, when running from a users workstation I run into issues.
The main issue seems to be the user id and password are incorrect. I am not sure where on the below I can add the system administrator (sa) user name and password for SQL Server. Please may I get some assistance.
My code:
Sub test()
Const SERVER = "SRV\ServerName"
Const DATABASE = "Test Database"
Dim fso As Object, ts As Object, ar
Dim ws As Worksheet
Dim iLastRow As Long, i As Long
Dim sql As String, timestamp As String
Dim Folder As String, SQLfile As String, LOGfile As String
Dim t0 As String: t0 = Timer
' query file and log filenames
timestamp = Format(Now, "YYYYMMDD_HHMMSS")
Folder = "\\SRV\Test Folder\"
SQLfile = Folder & timestamp & ".sql"
LOGfile = Folder & timestamp & ".log"
Set fso = CreateObject("Scripting.FileSystemObject")
' read data from sheet into array to build sql file
Set ws = ThisWorkbook.Sheets("UDF Update")
iLastRow = ws.Cells(Rows.Count, "N").End(xlUp).Row
If iLastRow = 1 Then
MsgBox "No data in Column N", vbCritical
Exit Sub
End If
ar = ws.Range("N2").Resize(iLastRow - 1).Value2
' connect to server and run query
Dim sConn As String, conn, cmd, n As Long
sConn = "Provider=SQLOLEDB;Server=" & SERVER & _
";Initial Catalog=" & DATABASE & _
";Trusted_Connection=yes;"
' open log file
Set ts = fso.CreateTextFile(LOGfile)
' make connection
Set conn = CreateObject("ADODB.Connection")
conn.Open sConn
' execute sql statements
Set cmd = CreateObject("ADODB.Command")
With cmd
.ActiveConnection = conn
For i = 1 To UBound(ar)
ts.writeLine ar(i, 1)
.CommandText = ar(i, 1)
.Execute
On Error Resume Next
Next
End With
ts.Close
conn.Close
MsgBox UBound(ar) & " SQL queries completed (ADODB)", vbInformation, Format(Timer - t0, "0.0 secs")
End Sub
If you use Trusted_Connection=yes, the SQL server accepts/rejects you via Windows authentication. It seems that your admin account is accepted by the server while other accounts are not.
Either the other accounts are added to the database server by the database admin or you need to provide credentials and set Trusted_Connection=no (or omit it as that is the defaults)
sConn = "Provider=SQLOLEDB;Server=" & SERVER & _
";Initial Catalog=" & DATABASE & _
";Trusted_Connection=no" & _
";User ID=MyUserID;Password=MyPassword;"
See https://learn.microsoft.com/en-us/sql/ado/guide/appendixes/microsoft-ole-db-provider-for-sql-server?view=sql-server-ver15

Execute SQL Server stored procedure in VBA with multiple outputs

I have a stored procedure in SQL Server that I am trying to execute from Excel via some VBA code. However, the stored procedure has two outputs (see below).
My record set is only pulling in the first table (added 0 error messages...) whereas I want to pull in the second table.
Image here: http://i.stack.imgur.com/LxyLi.png
Here is my code, compiled from other sources I found on here:
Sub RefreshBarcodes()
Dim Database As String
Dim con As ADODB.Connection
Dim strconn As String
Dim SQLServer As String
Dim Session As String
Dim strSQLCommandOne As String
Application.ScreenUpdating = False
Worksheets("Master").Activate
Database = Worksheets("Master").Cells(5, "H").Value
SQLServer = Worksheets("Master").Cells(4, "H").Value
Session = Worksheets("Master").Cells(6, "H").Value
'Connect to Database
Set con = New ADODB.Connection
strconn = "Provider=sqloledb; Data Source=" & SQLServer & ";Initial Catalog = " & _
Database & "; INTEGRATED SECURITY=SSPI; "
con.Open strconn
'Set SQL Commands
strSQLCommandOne = "set nocount on; exec spGetSessionSourceCounts 'HNW-CLU-001-024_01_0005'"
'Open Recordset
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
'Execute and copy to Excel
rs.Open strSQLCommandOne, strconn
rs.MoveFirst
Worksheets("Session").Activate
Cells(1, 1).Select
ActiveCell.CopyFromRecordset rs
rs.Close
Worksheets("Master").Activate
Cells(6, "H").Value = "Session updated"
con.Close
Application.ScreenUpdating = True
End Sub
Excel output: http://i.stack.imgur.com/b7i3B.png
I would love to be able to pull in the first (error message) and second results (session info), but mainly need only the second table. Thanks so much in advance!
To access the second recordset, you need to execute this line:-
'Activate the next available recordset
Set rs = rs.NextRecordset
If Not rs Is Nothing Then
'Add code in here
End If

Not able to connect with database

I am new in Excel VBA. I have ready made code which is written for machine of IP address 199.63.106.70. Now i want same code to be run for another machine 199.56.122.155. I have install MS SQL server 2008 R2 on new machine. I also checked with connection using Data Connection Wizard. Data is Fetched.
But when i try to get data by click on button it display error message "Error in Process".
Controller is Jumping from oCon.Open
How can this error will be solved? is format of connection string is correct?
User Id and Password is windows login credentials which is used in string.
Dim oCon As ADODB.Connection
Dim oRS As ADODB.Recordset
Dim rowcounter As Long
On Error GoTo errhandler
rowcounter = 2
Set oCon = New ADODB.Connection
oCon.connectionstring = "Driver={SQL Server};Server=199.63.106.70;Database=dashboard;User Id=dashboardadmin;Password=passwrd;"
oCon.Open
Set oRS = New ADODB.Recordset
oRS.ActiveConnection = oCon
oRS.Source = "SELECT HourlyReadingTimestamp, Hourlyreading,cost FROM MeterConsumptioNDetail where meterid=" & Range("J5").Value & " and HourlyreadingTimestamp between '" & Range("K5").Value & "' and '" & Range("L5").Value & " 23:59:59' order by HourlyreadingTimestamp"
oRS.Open
While Not oRS.EOF
Range("A" & rowcounter).Value = oRS.Fields(0).Value
Range("B" & rowcounter).Value = oRS.Fields(1).Value
Range("C" & rowcounter).Value = oRS.Fields(2).Value
rowcounter = rowcounter + 1
oRS.MoveNext
Wend
oCon.Close
If Not oRS Is Nothing Then Set oRS = Nothing
If Not oCon Is Nothing Then Set oCon = Nothing
MsgBox ("Data fetched successfully")
Exit Sub
errhandler:
MsgBox ("Error in process!")
End Sub
The connection string is incorrect if you want to use Integrated Security (Windows Login) use:
Driver={SQL Server};Server=199.63.106.70;Database=dashboard;Trusted_Connection=Yes;
The driver will deal with authentication based on the user running the process.

How to link Access table to SQL Server with VBA

I am trying to create a linked (or imported) table in Access with a SQL Server backend. Basically the business users periodically need a copy of the table [SQL Rulesnew] (yes, with the space, sigh) so we want to give them a little Access 2003 tool that will do the job on demand.
I did try using Docmd.TransferDataBase acTable but no luck
here is the code I am using:
Sub getData()
Dim sConnStr As String
Dim oTable As TableDef
Dim sDestinationTable As String
Dim dbs As Database
Dim tbl As DAO.TableDef
Dim tblLinked As DAO.TableDef
sDestinationTable = "SQL Rulesnew"
Set dbs = CurrentDb
' source table name has a SPACE (rolleyes!)
CurrentDb.CreateTableDef sDestinationTable
' got the below from a Data Link File (UDL)
sConnStr = "Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=MYDBNAME;Data Source=MYSERVERNAME"
' the below also failed!
'DoCmd.TransferDatabase acLink, "ODBC Database", "ODBC;Driver={SQL Server};Server=Fos;Database=Hermes_Rep;Trusted_Connection=Yes", acTable, "[Report SQLRulesnew]", "SQLRules" & VBA.Format(Now, "ddmmyyyy")
'If DCount("*", "MSysObjects", "[Name]='[SQL Rulesnew]' AND [Type] In (1, 4, 6)") > 0 Then
If IsTable(sDestinationTable) Then
DoCmd.DeleteObject acTable, sDestinationTable
End If
Set tblLinked = dbs.CreateTableDef(sDestinationTable)
Debug.Print "Linking the " & sDestinationTable
tblLinked.Connect = sConnStr
tblLinked.SourceTableName = sDestinationTable
dbs.TableDefs.Append tblLinked
tblLinked.RefreshLink
End Sub
Function IsTable(sTblName As String) As Boolean
'does table exists and work ?
'note: finding the name in the TableDefs collection is not enough,
' since the backend might be invalid or missing
Dim x
On Error GoTo Coventry
x = DCount("*", sTblName)
IsTable = True
Exit Function
Coventry:
Debug.Print Now, sTblName, Err.Number, Err.Description
IsTable = False
End Function
unfortunately I get an error could not find installable ISAM on the line dbs.TableDefs.Append tblLinked
what should I do?
thanks
Philip
I found the answer through trial and error...
Basically my table names in Access can have a space without using the [square brackets],
so the below command works fine (after deleting any existing object):
DoCmd.TransferDatabase _
acImport, _
"ODBC Database", _
"ODBC;Driver={SQL Server};Server=Fos;Database=Hermes;Trusted_Connection=Yes", _
acTable, _
"sourceTable", _
"targetTable"

Resources