Access 2007 VBA: Set Tabledef.Connect property to invalid path - ms-access

I've been asked to do some maintenance on an Access 2007 VBA database.
It has linked tables to another Access database in the same folder. It had hard-coded links to that database, so if the user copied the folder to a new folder, it tried to use the linked database in the original folder. They asked me to eliminate the danger of using the wrong linked database in that scenario.
I added code that runs when the database is opened, to make it reset the links to the database in it's own folder. If the linked database isn't there or was renamed, the user is prompted to browse to the correct database. So far so good.
But if the user cancels that dialog, I don't want to leave it connected to the wrong database. I want to set the linked tabledef's Connect property to the "correct" path even though the table is not there. Then the user will get an error that the linked table isn't there until they copy in the linked database -- rather than inadvertently use the wrong database.
When I use Resume Next to get past the error that is raised when I set the Connect property to a nonexistent database, the change doesn't stick, leaving it connected to the wrong database. So for now, I'm closing the database when that happens (after alerting the user that the linked database can't be found). That's safe in terms of not using the wrong database, but I don't think it's the ideal user experience.
So -- is it possible to set the Tabledef's Connect property to a nonexistent database?
Thanks,
Greg

is it possible to set the Tabledef's Connect property to a nonexistent database?
I don't think so. I recommend you delete all of the linked tables first, and then if there's no database to connect to, show an error saying so.
In order to relink the tables you will then need to have a local table in your frontend file that holds a list of all tables to be linked. Then you'll need to loop through that list every time you need to relink the tables, assuming that the links have all been deleted.

In order to update table links to render them invalid you need to
create a temporary copy of the back-end database (or perhaps a temporary copy of a "skeleton" back-end database with empty tables),
update the table links to point to the temporary database, and then
delete the temporary database.
For example, if I run the following code
Option Compare Database
Option Explicit
Sub MakeBadLink()
Const linkedTableName = "myLinkedTable" ' test value
Dim cdb As DAO.Database, tbd As DAO.TableDef
Dim tempFolder As String, linkedDb As String, tempDb As String
Dim fso As FileSystemObject
Set cdb = CurrentDb
linkedDb = Mid(cdb.TableDefs(linkedTableName).Connect, 11) ' remove ";DATABASE=" prefix
Set fso = New FileSystemObject
tempFolder = fso.GetSpecialFolder(TemporaryFolder) & "\"
tempDb = tempFolder & fso.GetFileName(linkedDb)
fso.CopyFile linkedDb, tempDb, True
Set tbd = cdb.TableDefs(linkedTableName)
tbd.Connect = ";DATABASE=" & tempDb
tbd.RefreshLink
Set tbd = Nothing
Set cdb = Nothing
fso.DeleteFile tempDb
Set fso = Nothing
End Sub
then any subsequent attempts to use [myLinkedTable] result in the error
Could not find file `C:\Users\Gord\AppData\Local\Temp\myDb.accdb'.

Related

Need to Change Linked Tables in MS Access DB with Username, Password and System DB

I have a front end DB, which needs to link to different back end DBs. To give you perspective, it relates to stand alone MDB files. The software in question builds a DB per company.
At the moment I am writing code within one of these MDB files.
For scalability I am now creating a new DB which will link to each MDB via code, and therefore my questions are as follows
How do I change the linked table location via code / VB so that the user can select the company / DB they want to work on
How do I do this with passing a username and password which is the same for all of the companies / DBs
And as per below we need to verify the username and password via the systemDB for it to open successfully.
As an FYI, this is how we open the DB on a standalone basis-
"C:\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE" "C:\temp\SAMPLE.mdb" /WRKGRP "C:\ProgramData\SOFTWARE\SYSTEM.mdw" /user:username /pwd:password
This is not a problem at all and is absolutely able to be accomplished given the clarification that you are using a single MDW file.
To clarify Microsoft Access Workgroup Security is essentially a "session" security model that applies directly to the front-end MDB file as you open it.
Your example command line means that Microsoft Access will open the SAMPLE.MDB front-end file using the workgroup file you specified.
Once Microsoft Access has opened SAMPLE.MDB under that workgroup file, you cannot change to another workgroup file within that "session" without closing Microsoft Access and re-opening under the new workgroup file.
FYI - it IS possible to open via code, a table in another MDB using another workgroup file within that connection, but in this manner, the table is only usable in code as a RecordSet (for example), you can't make it a linked table.
Anyway, back to your real issue. How to link a different back-end set of tables for each Company.
My recommendation would be to add a few fields to your Company table that defines the filename and location of each back-end file. For example:
Notice that the location can be a UNC path, or a mapped drive path. Or maybe you don't need to define a location in the table explicitly. Maybe all of the back-ends are in the same folder, or in a definable dynamic location like \Dallas\Dallas.mdb, \NewYork\NewYork.mdb, etc. As long as you can determine the location of each back-end in some manner, then you are fine.
Now, since you will likely have "global" front-end tables, maybe also some "global" linked back-end tables i.e. Common.mdb, and your company-specific back-end tables, I would recommend having a front-end table that defines the name of each of the tables that is involved only in the company-specific files. That way, we can easily loop through just those table names and make the link changes.
For the linking code, let's say that you have prompted the User for which Company they want, and you pass the CompanyID to a re-linking function:
Public Function ChangeCompanyLinks(CompanyID As Long) As Boolean
Dim db As DAO.Database
Dim ldb As DAO.Database
Dim tdf As DAO.TableDef
Dim rstCompany As DAO.Recordset
Dim rstTables As DAO.Recordset
Dim mssql As String
Dim dbFullPath As String
Dim retVal As Boolean
Set db = CurrentDb()
retVal = False
mssql = "SELECT * FROM [tblCompany] WHERE [CompanyID] = " & CompanyID
Set rstCompany = db.OpenRecordset(mssql, dbOpenSnapshot)
If Not rstCompany.BOF Then
dbFullPath = rstCompany("DBLocation") & "\" & rstCompany("DBName")
If Dir(dbFullPath) = rstCompany("DBName") Then
'NOTE: By opening a temporary constant link to the back-end during
' relinking, the relinking runs faster
Set ldb = OpenDatabase(dbFullPath)
mssql = "SELECT * FROM [tblLinkedTables] WHERE [FileType] = ""Company"""
Set rstTables = db.OpenRecordset(mssql, dbOpenSnapshot)
Do While Not rstTables.EOF
Set tdf = db.TableDefs(rstTables("TableName"))
tdf.Connect = ";DATABASE=" & dbFullPath
tdf.RefreshLink
rstTables.MoveNext
Loop
rstTables.Close
ldb.Close
retVal = True
Else
MsgBox "Unable to Locate Company File"
End If
End If
rstCompany.Close
ChangeCompanyLinks = retVal
Set rstCompany = Nothing
Set rstTables = Nothing
Set ldb = Nothing
Set tdf = Nothing
db.Close
Set db = Nothing
End Function
Obviously you will want to add error handling, and customize this a bit to fit your situation, but this code will re-link the specified tables to a new back-end.
Please note that if you eventually change to have your back-end tables in SQL Server (which I highly recommend), the re-linking code would need to be modified a bit. See this answer for more details on that.

How do I create copies of CurrentDb using VBA

I need to create copies of the CurrentDB using VBA (approx. 12 copies). The copies need to be clones of the master database containing all the same forms, queries, etc. except only a limited dataset.
DoCmd.CopyDatabaseFile seems to be made for this, but only works if you are using it to copy the DB to an MS SQL Server. As MS states on their website:
Copies the database connected to the current project to a Microsoft
SQL Server database file for export.
docmd.TransferDatabase only exports the data itself, but not the structure, forms, etc.
Code I have found on the web and adapted doesn't work and throws an error on the .CopyFile line saying:
Run-time error 52: Bad file name or number
This is the code
Sub CopyDB()
Dim external_db As Object
Dim sDBsource As String
Dim sDBdest As String
sDBsource = "\\group\bsc\groups\L\BDTP\Compliance\ComplianceData\Compliance Group Reporting.accdb"
sDBdest = "\\group\bsc\groups\L\BDTP\Compliance\ComplianceData\Compliance Group Reporting_2.accdb"""
Set external_db = CreateObject("Scripting.FileSystemObject")
external_db.CopyFile sDBsource, sDBdest, True
Set external_db = Nothing
End Sub
How can I fix the above line? Alternatively is there a direct command in Access to create a copy? The "create backup" function would be tailor made for this, but I can not find it in VBA.
Looks like you have an extra quote in sDBdest accdb"""
And for database copy you can also use
FileCopy sDBsource, sDBdest
Instead of Scripting object

Access linked table Connect property corrupted - How to fix (or delete)?

I have two Access (2016) databases on a company server. In database 'A' there is code that creates a linked table (in 'A') to a table in database 'B', performs some actions in database 'A' using the data in the linked table then deletes the linked table.
This has worked perfectly for several months but a couple of days ago it fell over.
On investigation I see that the linked table (in 'A') was not deleted, but the connection property of the table was reset to an empty string.
If I try to delete the linked table (in 'A') via the navigation pane I get the error 'Invalid use of Null'.
I've tried using code to update/restore the 'connection' property but that doesn't work.
I now have a table that I cannot delete.
Does anyone have any ideas how I can delete the table?
I've tried using code to update/restore the 'connection' property but that doesn't work.
I was able to recreate your issue by hacking an .accdb file and setting the .Connect property of a linked table to Null. Although ...
I was unable to delete the link (I got "Invalid use of Null", same as you), and
Compact and Repair Database did not fix the problem
... I was able to revive the link with the following VBA code:
Option Compare Database
Option Explicit
Sub ReviveBadLink()
Dim cdb As DAO.Database
Set cdb = CurrentDb
Dim tbd As DAO.TableDef
Set tbd = cdb.TableDefs("Clients")
tbd.Connect = ";Database=C:\Users\Public\Database1.accdb"
tbd.RefreshLink
End Sub
Once the link was revived I could then delete it as usual.

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/