How to refresh linked tables in an Access mdb when ODBC changes - ms-access

I can create an Access mdb and add a linked table to an Sql Server database via ODBC. If I change the Sql Server that the ODBC is connecting to with the ODBC control panel applet the mdb still connects to the original Sql Server until Access is restarted.
Is there a way to relink these linked server tables without restarting Access?
EDIT: I would like to do this in code

You can use the code below to refresh all ODBC tables in your Access project to a given DSN.
How to use it
Just copy the code in a new or existing VBA module and, where you want to refresh the links, call it with the proper DSN for the new ODBC connection:
RefreshODBCLinks "ODBC;DRIVER=SQL Server Native Client 10.0;" & _"
"SERVER=SQLSERVER;UID=Administrator;" & _
"Trusted_Connection=Yes;" & _
"APP=2007 Microsoft Office system;DATABASE=OrderSystem;"
Also, have a look at the Access help for the TableDef.RefreshLink method.
Code version 1
Classic way of relinking but Access may keep connection information in memory if the tables have been used before RefreshODBCLinks is called.
Public Sub RefreshODBCLinks(newConnectionString As String)
Dim db As DAO.Database
Dim tb As DAO.TableDef
Set db = CurrentDb
For Each tb In db.TableDefs
If Left(tb.Connect, 4) = "ODBC" Then
tb.Connect = newConnectionString
tb.RefreshLink
Debug.Print "Refreshed ODBC table " & tb.Name
End If
Next tb
Set db = Nothing
End Sub
Code version 2
This will completely re-create the ODBC linked tables: the old ones will be renamed, then new tables using the given DSN will be created before deleting the old linked version.
Please make sure you test this and maybe add some code to better handle errors as necessary.
Note also that the parameter dbAttachSavePWD passed during creation of the ODBC table will save the ODBC password (if any) in Access. Just remove it if that's not what you need.
Public Sub RefreshODBCLinks(newConnectionString As String)
Dim db As DAO.Database
Dim tb As DAO.TableDef
Dim originalname As String
Dim tempname As String
Dim sourcename As String
Dim i As Integer
Set db = CurrentDb
' Get a list of all ODBC tables '
Dim tables As New Collection
For Each tb In db.TableDefs
If (Left(tb.Connect, 4) = "ODBC") Then
tables.Add Item:=tb.Name, key:=tb.Name
End If
Next tb
' Create new tables using the given DSN after moving the old ones '
For i = tables.count To 1 Step -1
originalname = tables(i)
tempname = "~" & originalname & "~"
sourcename = db.TableDefs(originalname).SourceTableName
' Create the replacement table '
db.TableDefs(originalname).Name = tempname
Set tb = db.CreateTableDef(originalname, dbAttachSavePWD, _
sourcename, newConnectionString)
db.TableDefs.Append tb
db.TableDefs.Refresh
' delete the old table '
DoCmd.DeleteObject acTable, tempname
db.TableDefs.Refresh
tables.Remove originalname
Debug.Print "Refreshed ODBC table " & originalname
Next i
Set db = Nothing
End Sub
One last thing: if you're still getting issues that require that you restart Access for the changes to be visible, then have a look at my code in Restarting and compacting the database programmatically on my site.
Note: Code Version 2 was inspired in part from this Access Web article.

What version of Access are you using? In 2000, you can go to Tools>Database Utilities>Linked Table Manager to change your settings.

Related

Access/vba how to ceate server manager button in info tab with dsn less connection

I am converting an old Access/VBA database to Access 2010. In the old project there was a "SERVER" button on the file->Info form that managed the connections to a SQL Database. This provided a DSN less connection. After creating the database and importing from the older version the button is no longer there. I have been unable to find any reference to this and would like to know if anyone uses the same method for connecting and how to create the button.
Server Button
Create a button that calls this function. Pass the name of the linked table (strName) and the DSN name (strODBC).
Function EditConString(strName$, strODBC$)
Dim DB As DAO.database
Dim tdf As DAO.TableDef
tablename = strName
'replace with the access link name
Set DB = CurrentDb()
Set tdf = DB.TableDefs(tablename)
tdf.Connect = "ODBC;DSN=" & strODBC
'replace with the ODBC connection DSN name
tdf.RefreshLink
Set tdf = Nothing
DB.Close
End Function

Memory Exceeded Error in MS Access

I have the following procedure that I run (in an MS Access module) on a regular basis to switch the linked table connection strings from Test to Production and vice-versa:
Public Function TableRelink()
Dim db As Database
Dim strConnect As String
Dim rs As Recordset
Dim tdf As TableDef
strConnect = "ODBC;DRIVER=SQL Server;SERVER=MYTESTSERVER;Trusted_Connection=Yes;APP=Microsoft Office 2013;DATABASE=MyDB;"
'strConnect = "ODBC;DRIVER=SQL Server;SERVER=MYLIVESERVER;Trusted_Connection=Yes;APP=Microsoft Office 2013;DATABASE=MyDB;"
CurrentDb.TableDefs.Refresh
For Each tdf In CurrentDb.TableDefs
If tdf.Connect <> "" Then
tdf.Connect = strConnect
tdf.RefreshLink
End If
Next
MsgBox ("Done!")
End Function
The above has been working for months and months. About a week ago, the following error randomly popped up. Then, after a few minutes, without any intervention on my part, it would allow me to run the procedure again. Today, the error has come back.
Run-time error '3035': System resource exceeded.
It is thrown on this line: tdf.RefreshLink
I did a Google search and found an article out there talking about a hotfix (that wouldn't install on my machine), and another about editing a registry value (which didn't seem fix it). As I type this, the error has stopped popping up and I can again re-link my tables, so at this point, I can't really do any more troubleshooting. I was reading another SO post talking about the lock file, but couldn't really make heads or tails of the accepted answer, and I'm not really convinced it has anything to do with my particular scenario. Does anyone know what might be causing this and/or what can be done to prevent it?
For reference, I'm running Office 365 ProPlus on a Win10 64-bit machine.
First, do use your db object:
Public Function TableRelink()
Dim db As Database
Dim strConnect As String
Dim rs As Recordset
Dim tdf As TableDef
strConnect = "ODBC;DRIVER=SQL Server;SERVER=MYTESTSERVER;Trusted_Connection=Yes;APP=Microsoft Office 2013;DATABASE=MyDB;"
'strConnect = "ODBC;DRIVER=SQL Server;SERVER=MYLIVESERVER;Trusted_Connection=Yes;APP=Microsoft Office 2013;DATABASE=MyDB;"
Set db = CurrentDb
db.TableDefs.Refresh
For Each tdf In db.TableDefs
If tdf.Connect <> "" Then
tdf.Connect = strConnect
tdf.RefreshLink
End If
Next
MsgBox ("Done!")
Set td = Nothing
Set db = Nothing
End Function
However, another and a much faster method is to have both sets of tables linked permanently and then rename them for switching the database.
For example, to switch from Production to Test:
Table1 -> Table1_p
Table2 -> Table2_p
...
Table1_t -> Table1
Table2_t -> Table2
Of course, if you modify a table schema, you must relink as usual.

DSN-less connection to mysql server in ms-access not remembering user name and password

For ease of distribution I want all the mysql linked tables to be DSN-less. I also want to be able to relink the tables to a different server easily (for test purposes), so I'm doing the link setup in vba code. This is the code I use to setup/refresh any links:
Private Sub relink_mysql_tables(mysql_connection As String)
Dim db As Database
Set db = CurrentDb()
Dim tbldef As TableDef
For Each tbldef In db.TableDefs
If (tbldef.Attributes And TableDefAttributeEnum.dbAttachedODBC) Then
tbldef.Connect = mysql_connection
tbldef.RefreshLink
End If
Next
End Sub
The mysql_connection string I use is:
DRIVER={MySQL ODBC 5.1 Driver};Server=myserver;Database=mydatabase;Uid=myusername;Pwd=mypassword;Option=3
This is all fine and dandy and everything works until I close ms-access and reopen it. The user name and password seems to get forgotten. If I try and open a linked table, for example, I'm presented with a ODBC Connector pop-up asking me to enter user name and password.
I notice that after running the above relink code that if I hover the mouse pointer over a linked table (a table called 'tender' in this instance) it shows the current connection string, but with the user name and password omitted:
ODBC;DRIVER={MySQL ODBC 5.1 Driver};Server=myserver;Database=mydatabase;Option=3;TABLE=tender
I read elsewhere that adding ";Persist Security Info=True" to the connection string would work but it doesn't! The user name and password is still forgotten the next time I restart ms-access. My current solution is to re-run the relink code every-time the database is started but this seems like an unnecessary overhead to me. Is the a way for access to remember the user name and password within the linked tables?
I'm using Mysql5.5 and Access2007 by the way.
I found an answer with the help of this microsoft article. Rather than using the RefreshLink method, delete and recreate the link with the dbAttachedODBC option:
Public Sub relink_mysql_tables(mysql_connection As String)
Dim db As Database
Dim tblDef As TableDef
Dim sLocalTableName As String
Dim sRemoteTableName As String
' new collection '
Dim newTableDefs As New Collection
' current database '
Set db = CurrentDb()
' create new table defs '
For Each tblDef In db.TableDefs
If (tblDef.Attributes And TableDefAttributeEnum.dbAttachedODBC) Then
sLocalTableName = tblDef.Name
sRemoteTableName = tblDef.SourceTableName
' create new linked table def '
Set tblDef = db.CreateTableDef(sLocalTableName, dbAttachSavePWD, sRemoteTableName, mysql_connection)
newTableDefs.Add tblDef
End If
Next
' delete old table defs '
For Each tblDef In newTableDefs
db.TableDefs.Delete tblDef.Name
Next
' add new table defs to current database '
For Each tblDef In newTableDefs
db.TableDefs.Append tblDef
Next
The connection string is the same as before but with the addition of the prefix "ODBC;":
ODBC;DRIVER={MySQL ODBC 5.1 Driver};Server=myserver;Database=mydatabase;Uid=myusername;Pwd=mypassword;Option=3

Is there a way to tell if another Access db is linked to mine?

I have an old Access db with a plethora of lookup tables. Supposedly it was a warehouse of sorts for a bunch of other dept-made access apps to link to. We want to kill it. But, id there a way to find out if any app is currently linked to it?
You need the full path and filename of all the Access apps; this may not be possible.
For those you can, loop through all the files:
connect to each database to test for link.
Loop through all the tables in TestForLinkDatabase.TableDefs
Check to see if there is a .SourceTableName and the .Connect = YourLookupTableWarehouse for each table. I think the SourceTableName is an empty string for local tables.
Keep track of #3. You can optionally stop checking the rest of the tables if you find a single instance in the other file.
Again, it is not foolproof, but would be a good exercise to get a grip on all the Access apps floating around your company.
*Code does not exclude system tables.
Private Sub CheckToSeeIfLinked()
Dim Dbs As DAO.Database
Dim Tdf As DAO.TableDef
Dim Tdfs As TableDefs
Dim wrk As DAO.Workspace
Set wrk = DBEngine.Workspaces(0)
Dim TestDatabaseForLinks As String
TestDatabaseForLinks = "C:\FileNameToCheck.mdb"
Set Dbs = wrk.OpenDatabase(TestDatabaseForLinks)
Set Tdfs = Dbs.TableDefs
For Each Tdf In Tdfs
If Tdf.Connect <> "" Then
Debug.Print "Table: " & Tdf.Name & " - Is Linked To: " & Tdf.Connect
Else
Debug.Print "Table: " & Tdf.Name & " is not linked"
End If
Next
If Not (Dbs Is Nothing) Then
Dbs.Close
Set Dbs = Nothing
Set Tdfs = Nothing
End If
End Sub
Move it to another directory. Linked tables have hard-coded paths.
Not while the database isn't in use. When it is in use you should see an LDB/LACCDB file. You can open it with Notepad to see the workstation name.
If you are using Access security you will also see the Access userid. Otherwise you will see "Admin"
Opening the .ldb/.laccdb file using notepad will show you both who's currently in the database and some of the workstations which were in the database. When a person exits Access their workstation name and Access login id, Admin unless you are using Access security, are left in a "slot" or record in the ldb file. This slot or record may get overwritten the next time someone enters the MDB depending on what slot or record is available previous to it in the ldb file.
Determining the workstation which caused the Microsoft Access MDB corruption

Adding linked table to Access 2003 while keeping ODBC connection info in MDB

I have an Access 2003 database MDB where all of the tables exist as linked tables within SQL Server 2005. The MDB file contains all of the ODBC information that points to the correct SQL Server and log-on credentials (trusted connection).
What I would like to do is add a new linked table to the MDB file however I am not sure how to go about specifying the ODBC connection information. When I try to add a new linked table I keep getting prompted to locate or create a DSN file. I don't want to have to create a new DSN entry on every machine, rather I would like all that information stored within the Access MDB file itself.
In the existing database I can "hover" over the table names and see the ODBC connection info as a tool-tip. All I need to do is add another linked table using the same connection information.
I do have access to the SQL Server where the tables are linked to,. I have already created the new table I wanted to add. I just need to find a way to link to it.
For what it's worth, I'm lazy. I keep a DSN on my development machine, and use it to create new linked tables. I then run Doug Steele's code to convert the links to dsnless connections before distribution of the front end to the end users.
You can use the connection string from an existing table, or you can do something like:
''This is a basic connection string, you may need to consider password and so forth
cn = "ODBC;DSN=TheDSNName;Trusted_Connection=Yes;APP=Microsoft Office 2010;DATABASE=TheDatabaseName;"
There are a few was to connect a table:
sLocalName = "TABLE_SCHEMA" & "_" & "TABLE_NAME"
With CurrentDb
If DLookup("Name", "MSysObjects", "Name='" & sLocalName & "'") <> vbNullString Then
If .TableDefs(sLocalName).Connect <> cn Then
.TableDefs(sLocalName).Connect = cn
.TableDefs(sLocalName).RefreshLink
End If
Else
''If the table does not have a unique index, you will neded to create one
''if you wish to update.
Set tdf = .CreateTableDef(sLocalName)
tdf.Connect = cn
tdf.SourceTableName = "TABLE_NAME"
.TableDefs.Append tdf
.TableDefs.Refresh
End If
End With
This will produce a message box if the table does not have a unique index
DoCmd.TransferDatabase acLink, "ODBC Database", cn, acTable, "TABLE_NAME", sLocalName
I was able to add the table successfully and wanted to detail the steps here.
I added the new table by clicking "New" within Access and chose "Link Table"
When prompted with the Link file dialog I chose ODBC from the file type list box
I created a new DSN item (only used for initial linking to table)
Proceed with creating DSN and you will follow process of linking to the table created in SQL Server
Table should show up in Access
I then created the following sub routine in the code module. It essentially loops through all your tables in Access that have ODBC connections and sets the proper ODBC connection info into the Table definitions. You can delete the DSN you created previously as it is no longer needed.
Public Sub RefreshODBCLinks()
Dim connString As String
connString = "ODBC;DRIVER=SQL Server Native Client 10.0;" & _
"SERVER=<SQL SERVER NAME>;UID=<USER NAME>;" & _
"Trusted_Connection=Yes;" & _
"APP=<APP NAME>;DATABASE=<DATABASE NAME>"
Dim db As DAO.Database
Dim tb As DAO.TableDef
Set db = CurrentDb
For Each tb In db.TableDefs
If Left(tb.Connect, 4) = "ODBC" Then
tb.Connect = connString
tb.RefreshLink
Debug.Print "Refreshed ODBC table " & tb.Name
End If
Next tb
Set db = Nothing
End Sub
NOTE ... To execute the above SubRoutine I just typed in it's name into the "immediate" windows within the Access code module. You could also create a macro that executes this routine and then whenever you create a new table you could just run the macro.
Thanks to "Remou" for his answer and assistance!
P.S. If you are interested in APP=<APP NAME> in the connection string and what it is for check out this article. http://johnnycoder.com/blog/2006/10/24/take-advantage-of-application-name/