How to link tables with VBA code over ODBC - ms-access

Actually I use a ODBC-Connection to connect Ms Acces to tables of a PostgreSQL-DB. I connect them by using the External Data/Import ODBC-Link command. It works fine.
But how can I use VBA to link my tables?

When using VBA to link a table with ODBC, you can add and APP= argument to specify an application name that will generally show in the properties of the connection on your database server.
For example, here is a sample ODBC Connection string for a linked table:
ODBC;Driver={SQL Server};Server=MyServer\SQLExpress;Database=MyDatabase;APP=My App Title;Trusted_Connection=Yes;
My App Title is the string that will be your Application Name for that connection.
Update 1 In response to further comment by the OP:
Here is sample code to link a table via ODBC in VBA. To facilitate this, you also should always delete the ODBC linked table each time before re-linking it to make sure that your options are respected, and that Microsoft Access updates the schema for the linked table. This example shows a connection string for a SQL Server database, so all you would need to change is the connection string for your PostgreSQL-DB. The remaining VBA code would be the same.
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strConn As String
Dim ODBCTableName as String
Dim AccessTableName as String
Set db = CurrentDb()
ODBCTableName = "dbo.YourTable"
AccessTableName = "YourTable"
strConn = "ODBC;Driver={SQL Server};Server=YOURSERVER\SQLINSTANCE;Database=MYDATABASE;Trusted_Connection=No;UID=MyUserName;PWD=MyPassword"
db.TableDefs.Refresh
For Each tdf In db.TableDefs
If tdf.Name = AccessTableName Then
db.TableDefs.Delete tdf.Name
Exit For
End If
Next tdf
Set tdf = db.CreateTableDef(AccessTableName)
'===============================
'If your connection string includes a password
'and you want the password to be saved, include the following 3 lines of code
'to specify the dbAttachSavePWD attribute of the TableDef being created
'If you don't want to save the password, you would omit these 3 lines of code
'===============================
If InStr(strConn, "PWD=") Then
tdf.Attributes = dbAttachSavePWD
End If
tdf.SourceTableName = ODBCTableName
tdf.Connect = strConn
db.TableDefs.Append tdf

For some reason this code gives Run time error 3170 - Could not find installable ISAM. However, when you add ODBC; at the beginning of the connection string, then it works. So the connection string should look something like:
strConn = "ODBC;DRIVER={MySQL ODBC 5.2 Unicode Driver};" _
& "SERVER=servername;" _
& "DATABASE=databasename;" _
& "UID=username;PWD=password; OPTION=3"

Related

MS Access VBA Pass Through Query Connection Error when using Excel

I can connect to Oracle with a Passthrough query using ODBC to Oracle but the issue I have is because I have multiple databases that all use the same connections I want to store my credentials for the servers in an Excel encrypted file so nobody can see my passwords and only need to update in one place instead of every database but when I try and connect with my passthrough it doesnt work but does if I manually declare them in vba.
The Error Message is 3151 - ODBC - connection to '{Oracle in OraClientName}Server' failed
This is my code and dont know why it doesnt work? I tried with DSN and its the same result?
Function MyConnection()
On Error Resume Next
DoCmd.DeleteObject acQuery, "MY_TRANS"
Err.Clear
On Error GoTo 0
'''''GET EXCEL LOGIN DETAILS
Dim xlsApp
Set xlsApp = CreateObject("Excel.Application")
Dim WkBk As Excel.WorkBook
Set WkBk = xlsApp.WorkBooks.Open(FileName:="FILE LOCATION.xlsx", Password:="MYPASSWORD")
Dim LOGONNAME As String
Dim PWD As String
LOGONNAME = WkBk.Sheets(1).Range("B3").Value
PWD = WkBk.Sheets(1).Range("D3").Value
If Not (xlsApp Is Nothing) Then xlsApp.Quit
'end excel stuff
xlsApp.Quit
Set xlsApp = Nothing
'THIS WORKS IF I UNCOMMENT
'LOGONNAME = "MYNAME"
'PWD = "PASSWORD"
Dim db As DAO.Database
Dim ExtData As QueryDef
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT * FROM TABLE"
Set ExtData = db.CreateQueryDef("MY_TRANS")
ServerName = "MYSERVER"
ExtData.Connect = "ODBC;DRIVER={Oracle in OraClientName};Server=" & ServerName & ";DBQ=DBQNAME;UID=" & LOGONNAME & ";Pwd=" & PWD & ""
ExtData.SQL = strSQL
DoCmd.OpenQuery "MY_TRANS"
DoCmd.Close acQuery, "MY_TRANS"
ExtData.Close
db.Close
Set db = Nothing
END FUNCTION
#Andre Your Comment fixed the issue The Answer is if you get false after typing Debug.Print LOGONNAME, (LOGONNAME = "MYNAME") and doing the same for the password then you will need to go into the excel and check the details are the same or retype and check again. This fixed the issue for me.

How to Connect to an Access Database Using VBScript

I have an Access database for a client who wants to connect to and query the database using vbscript (so they can automate without actually opening the Access 2000 MDB). I can't figure out how to make the database connection.
I've tried several scripts, using both DAO and OLEDB. Below I've pasted the closest I've got, using an ODBC File DSN (I'm afraid using a System DSN would require extra work on the client's end, I'm trying to keep it simple).
Set objConnection = CreateObject("ADODB.Connection")
Set objRecordset = CreateObject("ADODB.Recordset")
'ERROR OCCURS HERE
objConnection.Open "FileDSN=D:\RLS.dsn;"
objRecordset.CursorLocation = adUseClient
objRecordset.Open "SELECT County FROM CountyTBL" , objConnection, adOpenStatic, adLockOptimistic
Here is the contents of RLS.dsn (I created this using Windows Control Panel so I am confident it's correct):
[ODBC]
DRIVER=Microsoft Access Driver (*.mdb)
UID=admin
UserCommitSync=Yes
Threads=3
SafeTransactions=0
PageTimeout=5
MaxScanRows=8
MaxBufferSize=2048
FIL=MS Access
DriverId=25
DefaultDir=D:\
DBQ=D:\RLS_be.mdb
The error message I got (and this was similar with the other 2 scripts I tried as well) was:
"Line 5, Char 4 Error: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified. Source: Microsoft OLE DB Provider for ODBC Drivers"
You can simply use ADO to connect to the file without setting up a DSN. This will be simpler for your client.
For Access 2000, 2002-2003 MDB, use the following connection string:
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\RLS_be.mdb"
For Access 2007, 2010, 2013 ACCDB:
"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=D:\RLS_be.accdb"
The overall connection code:
' Build connection string
Dim sConnectionString
sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\RLS_be.mdb"
' Create connection object
Dim objConnection
Set objConnection = CreateObject("ADODB.Connection")
' Open Connection
objConnection.open sConnectionString
' Get recordset from SQL query
Dim objRecordset
Dim sQuery
sQuery = "SELECT County FROM CountyTBL"
Set objRecordset = CreateObject("ADODB.Recordset")
objRecordset.CursorLocation = adUseClient
objRecordset.Open sQuery, objConnection, adOpenStatic, adLockOptimistic
Here is another version using the connection string for a MS-Access 2016 database. The example connects to the 'clients.accdb' database and retrieves the value of the 'ClientID' field of the record where the 'ClientName' is equal to 'Joe Smith', then it loops through the records returned by the SQL statement.
Note that the extra quotations in the SQL statement are used in order to handle the scenario in which the name might contain a single quot ('), for example O'Connor.
Dim oConn, oRS
Dim ClientName : ClientName = "Joe Smith"
Set oConn = WSH.CreateObject("ADODB.Connection")
oConn.Open "Provider=Microsoft.ACE.OLEDB.16.0; Data Source=C:\test\clients.accdb"
Set oRS = oConn.Execute("Select ClientID From Clients Where ClientName=""" & ClientName & """")
Do While Not(oRS.EOF)
'Do something with the record.
oRS.MoveNext
Loop
oRS.Close
oConn.Close

Link two Microsoft Access tables via vba

I'm trying to link two tables in different databases. What I've done is create a new table and then try to change the DESCRIPTION property to a path of a specific table in the other Database.
Set dbs = CurrentDb
thepath = "DATABASE=P:\Cadworx P&ID Implementation\3 Piping\P&IDs Jesus Test\Testproject\myTest.mdb;TABLE=Service"
Set tdf = dbs.TableDefs("ThisTable")
On Error Resume Next
tdf.Properties("Description") = "DATABASE=P:\Cadworx P&ID Implementation\3 Piping\P&IDs Jesus Test\Testproject\myTest.mdb;TABLE=Service"
If Err.Number = 3270 Then
Set prp = tdf.CreateProperty("Description", _
dbText, thepath)
tdf.Properties.Append prp
End If
This hasn't given me the desired results, as the link is never established. Can someone please tell me if this is the right way to do this or if there is a better way? Thanks for your help.
You can link to tables from other Access databases fairly easily using Access' in-built features.
Depending on the version of Access you're using, there should be an option to import/link to other data sources, including another Access database:
This starts an import/link wizard. Browse to the database file you want to link to:
Specify whether you want to import or link to data objects within the database file you browsed to (in this case, link):
Select the objects you want to link to:
Linked objects will appear in your navigation pane with a blue arrow denoting they are a linked object, rather than something stored locally to your current database:
You should then be able to use your linked tables as if they were any other kind of table in your database.
Here is the solution to the problem.
Dim dbs As DAO.Database
Dim tdf As DAO.TableDef
Dim strDbFile As String
Dim strConnect As String
Dim strSourceTableName As String
Dim strLinkName As String
Dim f As Object
Dim varfile As Variant
Set f = Application.FileDialog(3) 'Windows Explorer, 3 means file picker. 4 Is for folder, 1 to open dialog box, 2 to save as
f.show 'Show Windows explorer
With f
f.allowmultiselect = False
For Each varfile In .selecteditems
strDbFile = varfile 'File selected assigned to source database file
Next
End With
strSourceTableName = "Service" 'Source Table
strLinkName = "Service" 'Final table name once link has been established
strConnect = "MS Access;PWD=" & strPassword & ";DATABASE=" & strDbFile
Set dbs = CurrentDb
Set tdf = dbs.CreateTableDef
tdf.Connect = strConnect 'Establish link between databases
tdf.SourceTableName = strSourceTableName
tdf.Name = strLinkName
dbs.TableDefs.Append tdf
As Gustav said, the solution was along what he posted. New to access so I didn't really know what the DAO library is. Thanks for your help anyway!

Link Table via DAO

So I am essentially trying to link a table via DAO from an ACCDB that is password-encrypted into the DB I am working in. The premise of what I am doing is that the data is sort of "user sensitive" so I do not want to let every user have access to this table in my front end (have the front-end/back-end split), only specific users. What I would like to do is to check the username of the computer, then allow the front-end to link to the data if the username is correct:
Select Case Environ("username") 'select case user environment name
Case "jsmith" 'if username is jsmith then
Set db = DAO.OpenDatabase("Audit.accdb", False, False, _
";pwd=adaudit12") 'create connection to my other db
Set tbl = db.TableDefs(14) 'selects the table via index
CurrentDb.TableDefs.Append tbl 'create a link to my current DB with this table (throws ex here)
Case Else
End Select
This returns runtime error '3367' Cannot Append. An object with that name already exists in the collection.
So I thought to do this:
For Each tbl In CurrentDb.TableDefs
Msgbox tbl
Next tbl
But the table doesnt exist in my database, so what should I do?
Take a closer look at how you're examining the table names in CurrentDb. This line throws error #13, "Type mismatch", on my system:
Msgbox tbl
I think you should ask for the TableDef.Name instead:
Msgbox tbl.Name
However, I'm not sure that's the only problem here. You seem to be trying to link to a table in another db file by copying that TableDef and adding it to CurrentDb.TableDefs. IF you can make that work, it won't give you a link to the source table, it would make a new copy in CurrentDb. But I'm skeptical whether it can work at all.
You could create a new TableDef object, set its Name, Connect, and SourceTableName properties, then append it to CurrentDb.TableDefs. Include the database password in the Connect property.
Here is code tested in Access 2007.
Dim db As DAO.Database
Dim tdf As DAO.TableDef
Dim strConnect As String
Dim strDbFile As String
Dim strLinkName As String
Dim strPassword As String
Dim strSourceTableName As String
strDbFile = "C:\share\Access\MyDb.accdb"
strPassword = "foo"
strSourceTableName = "Contacts"
strLinkName = "link_to_contacts"
strConnect = "MS Access;PWD=" & strPassword & _
";DATABASE=" & strDbFile
Debug.Print strConnect
Set db = CurrentDb
Set tdf = db.CreateTableDef
tdf.Connect = strConnect
tdf.SourceTableName = strSourceTableName
tdf.Name = strLinkName
db.TableDefs.Append tdf
Set tdf = Nothing
Set db = Nothing
Tables and queries share the same name space in MS Access. Chances are you have a query with the same name as the table you are trying to link.
Also, Environ("username") is easily spoofed. Consider using the API function GetUserName instead. Of course, if you need real security you'll want to upgrade your back-end to SQL Server (Express) or some other RDBMS.

Editing Linked Table Information In Access 2003

I have an Access 2003 database with linked tables to a SQL Server 2005 database. The user information (the password) that is used to create an ODBC connection between Access and SQL Server was recently updated.
When I open the Access database, and try to edit the Linked table information I am then able to open the tables and see my data. However, when I close Access and and reopen the Access database it appears the password informtion has revereted back and I get an ODBC connection error.
Anyone know what I am doing incorrectly?
As a follow up, it appears we have about a dozen Access databases with numerous linked tables that all need this update. Is this the best way to update this information? The linked tables seem to have been created using different machines as the Workstation-ID specified in the ODBC connection is different.
Write a routine, that update the Connect Property from the TableDef and save the change with RefreshLink.
The problem with Linked Table Manager (LTM), is when you have linked tables that are in fact links to SQL Views. In that case, LTM will relink the "tables" without reassigning them the proper PK, and they will become non updatable.
I have written some code that I used to start from VBE, it is a quick and dirty thing, but you could surely adapt that if you need it.
There are 2 subs, one for the tables, and one for the passthru queries.
Option Compare Database
option explicit
Const kOld = "remote.g" 'string to identify old server
'new server odbc string
Const kConnLux = "ODBC;DRIVER=SQL Server Native Client 10.0;SERVER=xxxx;UID=yyyy;PWD=zzzz;"
Sub UpdateTables()
Dim db As Database, td As TableDef
Dim hasIndex As Boolean, strSql As String
Set db = CurrentDb
For Each td In db.TableDefs
If InStr(1, td.Connect, kOld) > 0 Then 'lien vers CE serveur ?
If td.Name Like "dbo_vw*" And td.Indexes.count = 1 Then 'table = vue attachee --> pbl de clef primaire
strSql = "CREATE INDEX " & td.Indexes(0).Name & " ON [" & td.Name & "](" & td.Indexes(0).Fields & ")"
' convert field list from (+fld1;+fld2) to (fld1,fld2)
strSql = Replace(strSql, "+", "")
strSql = Replace(strSql, ";", ",")
hasIndex = True
Else
hasIndex = False
End If
td.Connect = kConnLux
td.RefreshLink
Debug.Print td.Name
If hasIndex And td.Indexes.count = 0 Then
' if index now removed then re-create it
CurrentDb.Execute strSql
End If
End If
Next td
Debug.Print "Done"
End Sub
Sub UpdateQueries()
Dim db As Database
Dim td As QueryDef
Set db = CurrentDb
For Each td In db.QueryDefs
If InStr(1, td.Connect, kOld) > 0 Then
td.Connect = kConnLux
Debug.Print td.Name, td.Connect
End If
Next td
End Sub