Preventing MSAccess linked tables from having a dbo_ prefix? - ms-access

Is there a way to prevent MSAccess from concatenating 'dbo_' as the prefix to tables linked from a SQL Server db?

No. Microsoft Access' native naming convention process will force the name <schema>_<ObjectName> as your default table name. There are no controls or settings which will allow you to change that, except in code. It's rather complex and goes beyond the scope of this question, but if you do the linking in code (which I do) then you can store the TableAlias and create the linked table name that way.

You can write your table definition in the code to attach the table as below where
strTableAlias is your display name in Access
strTableName is your table name with schema <schema>.<ObjectName>.
Dim td As DAO.TableDef
set td = CurrentDb.CreateTableDef(strTableAlias, dbAttachSavePassword, _
strTableName, strConnectionStr)
CurrentDb.TableDefs.Append td

If you don't do the linking in code as mentioned by Johnny you can rename the links with this VBA code:
Public Sub Remove_DBO_Prefix()
Dim obj As AccessObject
Dim dbs As Object
Set dbs = Application.CurrentData
'Search for open AccessObject objects in AllTables collection.
For Each obj In dbs.AllTables
'If found, remove prefix
If Left(obj.Name, 4) = "dbo_" Then
DoCmd.Rename Mid(obj.Name, 5), acTable, obj.Name
End If
Next obj
End Sub
Courtesy https://www.microsoftaccessexpert.com/Microsoft-Access-Code-RemoveDBOPrefix.aspx
If you're doing this with the idea of using queries that you generate in Access outside of Access remember that Access creates it's own sql dialect so you may need to convert double quotes to single and # to ' among other things.

Related

Updating an Access Table with a CSV File Automatically

Problem Background:
I have a Powershell script that I can execute from my Microsoft Access Form that scans through file folders that contain information on different facilities, and produces a CSV that looks something like:
SiteCode FacilityNumber DocumentType HyperlinkPath
DKFZ 10 DD1400 C:\FACILITIES DATABASE\path
DKFZ 10 FLRPLN C:\FACILITIES DATABASE\path
SMQL 17 P1 C:\FACILITIES DATABASE\path
SMQL 17 P2 C:\FACILITIES DATABASE\path
So that way every time new files are added to those folders, I can just run this script and produce an updated list of everything I have:
C:\...\Output\scanResults.csv
All I need now is to take that CSV file and update (or even overwrite) a Table that I have in an Access database, which has relationships to other tables and is used by various Queries and Forms in the database. The CSV columns are already named and formatted in the same way as the Access Table.
I've looked at and tried to replicate the following threads:
VBA procedure to import csv file into access
Access Data Project Importing CSV File In VBA
VBA Import CSV file
The closest answer I found is:
Sub Import()
Dim conn as new ADODB.Connection
Dim rs as new ADODB.Recordset
Dim f as ADODB.field
conn.Open "DRIVER={Microsoft Text Driver (*.txt; *.csv)};DBQ=c:\temp;"
rs.Open "SELECT * FROM [test.txt]", conn, adOpenStatic, adLockReadOnly, adCmdText
While Not rs.EOF
For Each f In rs.Fields
Debug.Print f.name & "=" & f.Value
Next
Wend
End Sub
But this obviously won't write the data into the table, and I could not understand what the author was trying to say with respect to changing Select to Insert.
I've also found:
DoCmd.TransferText acImportDelim, "YourCustomSpecificationName", _
"tblImport", "C:\SomeFolder\DataFile.csv", False
Since both of these are from 2010, I wonder if there isn't a better way to accomplish this in Access 2013. And while I can do this all manually, I would like to incorporate it into the VBA code I use to tell Powershell to produce the CSV, that way I can make it and then upload it immediately.
Any help or suggestions are greatly appreciated. I'm still very green to Access, VBA, and SQL statements in general, so this has been very much a "learning as I go" process.
I prefer to use SQL clauses and queries to import such data. The details depend on your exact configuration, but it tends to look something like this:
SELECT *
INTO MyTable
FROM [Text;FMT=CSVDelimited;HDR=No;DATABASE=C:\...\Output].[scanResults#csv]
Or append the information to the table instead:
INSERT INTO MyTable
(SiteCode, FacilityNumber, DocumentType, HyperlinkPath)
SELECT *
FROM [Text;FMT=CSVDelimited;HDR=No;DATABASE=C:\...\Output].[scanResults#csv]
This allows you to do checks before importing (using a WHERE clause), import only specific values, and allows you to customize a lot without using external files.
DATABASE= is followed by your folder name (use {} if there are characters that need escaping in there), and then followed by your file name with . replaced with #.
You can execute it by either saving it as a query, or using it as a string in either VBA or a macro. Note that I rarely recommend macro's, but you can execute them using a scheduled task and close Access after importing.
To backup and restore a relation before and after updating, you can use the following functions:
Public Function DeleteRelationsGiveBackup(strTablename As String) As Collection
Dim ReturnCollection As Collection
Set ReturnCollection = New Collection
Dim i As Integer
Dim o As Integer
Do While i <= (CurrentDb.Relations.Count - 1)
Select Case strTablename
Case Is = CurrentDb.Relations(i).Table
ReturnCollection.Add DuplicateRelation(CurrentDb.Relations(i))
o = o + 1
CurrentDb.Relations.Delete CurrentDb.Relations(i).NAME
Case Is = CurrentDb.Relations(i).ForeignTable
ReturnCollection.Add DuplicateRelation(CurrentDb.Relations(i))
o = o + 1
CurrentDb.Relations.Delete CurrentDb.Relations(i).NAME
Case Else
i = i + 1
End Select
Loop
Set DeleteRelationsGiveBackup = ReturnCollection
End Function
Public Sub RestoreRelationBackup(collRelationBackup As Collection)
Dim relBackup As Variant
If collRelationBackup.Count = 0 Then Exit Sub
For Each relBackup In collRelationBackup
CurrentDb.Relations.Append relBackup
Next relBackup
End Sub
Public Function DuplicateRelation(SourceRelation As Relation) As Relation
Set DuplicateRelation = CurrentDb.CreateRelation(SourceRelation.NAME, SourceRelation.Table, SourceRelation.ForeignTable)
DuplicateRelation.Attributes = SourceRelation.Attributes
Dim i As Integer
Dim fldLoop As Field
Do While i < SourceRelation.Fields.Count
Set fldLoop = DuplicateRelation.CreateField(SourceRelation.Fields(i).NAME)
fldLoop.ForeignName = SourceRelation.Fields(i).ForeignName
DuplicateRelation.Fields.Append fldLoop
i = i + 1
Loop
End Function
And then, when importing:
Dim colRelBackup As Collection
Set colRelBackup = DeleteRelationsGiveBackup("MyTable")
'Delete MyTable
'Import new version
RestoreRelationBackup colRelBackup
(Note that the code is quite long, developed for a project several years ago, and not extensively tested. If a field name/type is not exactly like how it was before the import, the restore of the backup might fail and the relations will be permanently lost).
So some high level architect advice: replacing data versus replacing table
It is easier replacing data - - the new incoming data must be the exact same structure as the existing table (i.e. same field names and no new fields).
just fire a Delete Query to the existing table that clears out all records
then fire an Append Query to the linked CSV file that writes all those records into the existing table
very simple really.
You can replace the tables if you must - and you are already down this path. You can delete those table relationships entirely. That table relationship feature is useful - but not mandatory. You can create relationships at the query level as an alternative. Essentially the table relationships just auto create the query level relationships. If you delete the table relationships then one must simply create the table relationships at the query level manually - they don't automatically appear. Note however that if one is relying on cascade deletes or referential integrity, then removing table relationships will undo that - so you should check these points.
Deleting Table Relationships will not break any existing queries. Their table relationship join lines will remain intact.

Why does my database object show no Recordsets?

Why does my database object show no Recordsets? And why does it not show a Connection? The key bit of code is:
Public Sub PrintRecords()
Dim dbCurr As DAO.Database
Set dbCurr = CurrentDb
Dim rsCourses as Recordset
Set rsCourses = CurrentDb.OpenRecordset(“Courses”)
End Sub
Here is my screenshot, where the database has tables (upper left), but the CurrentDB object has a name but no Recordsets (in the locals window below.)
For what it’s worth, this is in Access 2013, following this tutorial to manipulate the database, stopping on the error “Run-time error ‘3078’: The Microsoft Access database engine cannot find the input table or query”. But the problem seems to be deeper than that.
You have typographic quotes in there, use straight ones "".
And use your assigned database object:
Set rsCourses = dbCurr.OpenRecordset("Courses")
And please don't post only screenshots of code, copy & paste the code itself as text.

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

Using access to refer to objects within access

I have a basic table in access with several populated fields. I would like to explore if there is a way, preferably through the GUI (or maybe through SQL), to add a field containing the name of the table itself. I see only the following data formats for fields: Short text, Long text, number, Date/time, Currency, Autonumber, Yes/No, OLE Object, Hyperlink, Attachment and Calculated. There is nothing pertaining to data object parameters themselves such as table, field or query names or parameters...
You can access the meta data of the database via VBA (Visual Basic for Applications) macros.
For example, this can show all table names:
Option Compare Database
Public Sub Test()
Dim database As DAO.database
Dim tableDef As DAO.tableDef
Set database = CurrentDb
For Each tableDef In database.TableDefs
MsgBox tableDef.Name
Next
End Sub

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

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'.