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.
Related
I tried using Pass-Through query to call mysql stored procedure from MS Access VBA. This is the code:
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
Set qdf = CurrentDb.CreateQueryDef("")
qdf.Connect = "DRIVER={MySQL ODBC 5.3 Unicode Driver};SERVER=localhost;PORT=3306;DATABASE=accounting_supp_db;User=xxx;Password=xxx;Option=3"
qdf.SQL = "CALL MyStoredProcedure('10156','2021-03-03','2021-03-10')"
qdf.ReturnsRecords = True
Set rst = qdf.OpenRecordset
rst.Close
Set rst = Nothing
Set qdf = Nothing
But it return error 3305: Invalid Connection String In Pass-Through Query. Is there somothing wrong with the connection string?
thx
Well, one way to figure this out?
Simply use the external data from the ribbon - and link a table from access to MySQL. Get that working - once you do?
Then do this in your code:
dim rst as DAO.RecordSet
With CurrentDB.queryDefs("MyPTQuery")
.Connection = currentdb.tableDefs("The working linked table").Connection
.SQL = "CALL MyStoreProc('10156','2021-03-03','2021-03-10')"
set rst = .OpenRecordSet
End if
You could I suppose add to above .ReturnsRecords = True, but then again?
Well, create that one PT query - set the connection correct. Then you can do this in code:
Dim rst1 as DAO.RecordSet
Dim rst2 as DAO.ReocrdSet
With Currentdb.tableDefs("MyPTQuery")
.SQL = "CALL MyStoredProcedure('10156','2021-03-03','2021-03-10')"
set rst1 = .OpenRecordSet
END with
With Currentdb.tableDefs("MyPTQuery")
.SQL = "CALL MyStoredProcedure('10777','2021-04-03','2021-05-10')"
set rst2 = .OpenRecordSet
End With
Note how we don't mess with creating a query def. And note how we can use the ONE pt query over and over.
And it gets better Say you want that stored procedure for a report? Well base the report on "MyPTQuery"
Then do this:
With Currentdb.tableDefs("MyPTQuery")
.SQL = "CALL MyStoredProcedure('10777','2021-04-03','2021-05-10')"
End With
docmd.OpenReport "rptCustomerProjects", acViewPreview
In fact, you can write the above like this:
Currentdb.tableDefs("MyPTQuery").SQL = "CALL MyStoredProcedure('10777','2021-04-03','2021-05-10')"
docmd.OpenReport "rptCustomerProjects", acViewPreview
So I quite much recommend that you SAVE the connection string in the PT query. That way, your code has no messy connection strings - and such connections are now "out" of your code - you can easy change the connection for the whole database - not change any code.
So, when you run your table re-link code? Have that re-link code ALSO update any PT query. That way you can now re-link and point your application to a test database, or production one, or whatever. So, no connection strings in code are the result of the above.
Regardless of above? Get a linked table working - and then use that "steal" the known connection from the linked table and shove it into the connection for the PT query as per first example above.
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
I have script that creates a pass through query using a connection string and a password. It works on first connection attempt: fails until the user enters the correct password. If the connection string is lost or the user needs to renter it for any reason, it will succeed no matter what password is passed through the connection string.
I've tried created named queryDefs and removing them, unique and non-unique. If this is the way it has to be, I'll work with it, but I don't like not understanding what's going on, so if anyone has any insight, that would be great. Thanks!
Dim db As DAO.Database, qDef As QueryDef, rst As DAO.Recordset
Set db = CurrentDb
Set qDef = db.CreateQueryDef(vbNullString)
With qDef
.Connect = connStr
.sql = sql
.ReturnsRecords = True
Set rst = .OpenRecordset(dbOpenSnapshot, dbSQLPassThrough)
End With
If readAll Then
With rst
If Not .EOF And Not .BOF Then
.MoveLast
.MoveFirst
End If
End With
End If
Set PassThroughRecordset = rst
This is by design, connections with user/password are cached as long as Access runs, and server/db stay the same.
See here and the linked blog post:
Save password for ODBC connection to MS SQL server from MS Access 2007
How to avoid prompting for user id and password in MSAccess 2003
Hey.
I have the main access database located on a stand alone PC off the network and i have a access database with linked tables on the network linked back to the stand alone PC. I have linked the tables by creating a network share to the stand alone PC and linking them though a path. Can i set it up so that when the database is opened it automatically updates the linked tables.
Ben
You can. I often find it convenient to use a small check form that runs on start-up (set through start-up options) and checks a variety of things, including linked tables. To this end, I also hold a table of linked tables on the local machine, although a list of linked tables can be obtained by iterating through the TableDefs collection, I think it is slightly safer to keep a list.
The check form can check all links and if a link is broken or missing, either ask the user for a new location or use a fixed location. If no problems are found, the form can close itself and open a menu or other form.
In the case of linking to a linked table, it is possible to get the connection to use from:
CurrentDB.TableDefs("TableName").Connection
Here are some more notes:
Sub RelinkTables(Optional strConnect As String = "")
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL
Dim tdf As DAO.TableDef
On Error GoTo TrapError
Set db = CurrentDb
If strConnect = "" Then
''Where Me.txtNewDataDirectory is a control on the check form
strConnect = "MS Access;PWD=databasepassword;DATABASE=" & Me.txtNewDataDirectory
End If
''Table of tables to be linked with two fields TableName, TableType
Set rs = CurrentDb.OpenRecordset("Select TableName From sysTables " _
& "WHERE TableType = 'LINK'")
Do While Not RS.EOF
''Check if the table is missing
If IsNull(DLookup("[Name]", "MSysObjects", "[Name]='" & rs!TableName & "'")) Then
Set tdf = db.CreateTableDef(RS!TableName, dbAttachSavePWD, _
rs!TableName, strConnect)
''If the table is missing, append it
db.TableDefs.Append tdf
Else
''If it exists, update the connection
db.TableDefs(rs!TableName).Connect = strConnect
End If
db.TableDefs(rs!TableName).RefreshLink
RS.MoveNext
Loop
Set db = Nothing
RS.Close
Set RS = Nothing
Exit_Sub:
Exit Sub
TrapError:
HandleErr Err.Number, Err.Description, "Relink Tables"
End Sub
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.