Identifying where a table begins in a Word doc - ms-access

I have a specific work doc that is produced daily which includes a paragraph of text followed by a table with a bunch of customer data. I need to import that data into an Access table.
I've found code, which I'll include below, which does just that. However it's not working as intended. Rather it's not working at all. I anticipate that it's because the word doc begins not with a table, but text.
So I have two options. 1) Find a way to format each document so it contains only the table (I'll have to automate this because we receive dozens of these files each day) or 2) adjust the code so that it detects only the table in the doc.
Is there a good way of doing either of these things?
Option Compare Database
Private Sub cmdImport_Click()
Dim appWord As Word.Application, doc As Word.Document
Dim dbs As DAO.Database, rst As DAO.Recordset, strDoc As String
Set appWord = CreateObject("Word.Application") 'establish an instance of word
strDoc = CurrentProject.Path & "\cmoSheet.docx" 'set string to document path and file
Set doc = appWord.Documents.Open(strDoc) 'establish the document
Set dbs = CurrentDb 'establish the database to use (this is our current Database)
Set rst = dbs.OpenRecordset("cmoSheetTbl") 'establish the recordset
With doc.Tables(1) 'target table 1 in cmoSheet.docx
For i = 2 To .Rows.Count 'cycle through rows in Tables(1) [we skip the first row because the table has headers]
With rst
.AddNew 'creating a new record
![ReviewerName] = doc.Tables(1).Cell(i, 1).Range.Text
![ProductDesc] = doc.Tables(1).Cell(i, 2).Range.Text
![NPI] = doc.Tables(1).Cell(i, 3).Range.Text
![LastName] = doc.Tables(1).Cell(i, 5).Range.Text
![FirstName] = doc.Tables(1).Cell(i, 6).Range.Text
![ProviderType] = doc.Tables(1).Cell(i, 7).Range.Text
![Specialty] = doc.Tables(1).Cell(i, 8).Range.Text
![BatchID] = doc.Tables(1).Cell(i, 9).Range.Text
![AdditionalDocs?] = doc.Tables(1).Cell(i, 10).Range.Text
.Update 'update the whole record
End With
Next 'go to next row in Tables(1)
End With
rst.Close: Set rst = Nothing 'close and clear recordset
db.Close: Set rst = Nothing 'close and clear database
doc.Close: Set doc = Nothing 'close and clear document
appWord.Quit: Set appWord = Nothing 'close and clear MS Word
End Sub

A nested With must be related to the outer With. In addition, adding Option Explicit will reveal a couple of errors in your code.
db.Close: Set rst = Nothing
should be:
dbs.Close: Set dbs= Nothing
Since you create an early binding to Word when declaring the variables, you can simply use the New keyword to create an instance:
Dim appWord As Word.Application, doc As Word.Document
Set appWord = New Word.Application
If you want to create a late bind to Word, remove the reference to it and declare the variable(s) as Object:
Dim appWord As Object, doc As Object
Set appWord = CreateObject("Word.Application")
Try this:
Private Sub cmdImport_Click()
Dim appWord As Word.Application, doc As Word.Document
Dim dbs As DAO.Database, rst As DAO.Recordset, strDoc As String
Set appWord = New Word.Application 'establish an instance of word
strDoc = CurrentProject.Path & "\cmoSheet.docx" 'set string to document path and file
Set doc = appWord.Documents.Open(strDoc) 'establish the document
Set dbs = CurrentDb 'establish the database to use (this is our current Database)
Set rst = dbs.OpenRecordset("cmoSheetTbl") 'establish the recordset
With doc.Tables(1) 'target table 1 in cmoSheet.docx
Dim i As Integer
For i = 2 To .Rows.count 'cycle through rows in Tables(1) [we skip the first row because the table has headers]
rst.AddNew 'creating a new record
rst![ReviewerName] = .Cell(i, 1).Range.Text
rst![ProductDesc] = .Cell(i, 2).Range.Text
rst![NPI] = .Cell(i, 3).Range.Text
rst![LastName] = .Cell(i, 5).Range.Text
rst![FirstName] = .Cell(i, 6).Range.Text
rst![ProviderType] = .Cell(i, 7).Range.Text
rst![Specialty] = .Cell(i, 8).Range.Text
rst![BatchID] = .Cell(i, 9).Range.Text
rst![AdditionalDocs?] = .Cell(i, 10).Range.Text
rst.Update 'update the whole record
Next 'go to next row in Tables(1)
End With
rst.Close: Set rst = Nothing 'close and clear recordset
dbs.Close: Set dbs = Nothing 'close and clear database
doc.Close: Set doc = Nothing 'close and clear document
appWord.Quit: Set appWord = Nothing 'close and clear MS Word
End Sub

Related

Microsoft Access Database - Downloading ALL attachments from MULTIPLE entries

I am currently trying to download many .doc files that are attached to the Microsoft Access record under the "Attachment" field which is labeled as "File/Attachment". However, I need the ability to run a query (Search By Loss Incident) which I did prior and then run the macro to download ALL the attachments from multiple records. This is my code below, I need some help with it! I am getting an error of "This expression you entered has a function containing the wrong number of arguments".
Option Compare Database
Public Function SaveAttachmentsTest(strPath As String, Optional strPattern As String = "*.*") As Long
Dim dbs As DAO.database
Dim rst As DAO.Recordset
Dim rsA As DAO.Recordset2
Dim fld As DAO.Field2
Dim strFullPath As String
'Get the database, recordset, and attachment field
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("Search By Loss Incident Name")
Set fld = rst("File/Attachment")
'Navigate through the table
Do While Not rst.EOF
'Get the recordset for the Attachments field
Set rsA = fld.Value
'Save all attachments in the field
Do While Not rsA.EOF
If rsA("FileName") Like strPattern Then
'To Export the data, use the line below
strFullPath = "C:\Users\Emmanuel\Desktop\Test" & "\" & rsA("FileName")
'Make sure the file does not exist and save
If Dir(strFullPath) = "" Then
rsA("FileData").SaveToFile strFullPath
End If
'Increment the number of files saved
SaveAttachmentsTest = SaveAttachmentsTest + 1
End If
'Next attachment
rsA.MoveNext
Loop
rsA.Close
'Next record
rst.MoveNext
Loop
rst.Close
dbs.Close
Set fld = Nothing
Set rsA = Nothing
Set rst = Nothing
Set dbs = Nothing
End Function
Introduce a local variable:
<snip>
Dim SavedAttachments As Long
<snip>
' Increment the number of files saved.
SaveAttachments = SaveAttachments + 1
End If
<snip>
Set fld = Nothing
Set rsA = Nothing
Set rst = Nothing
Set dbs = Nothing
' Return the count of saved files.
SaveAttachmentsTest = SaveAttachments
End Function

Duplicating just one record on import

This may seem like a rather odd question but I would like to duplicate the first record (preferably to the next spot in the database). I want to do this as our clients are asking for samples of our mail merge and it has to be a live file. I currently use a dialog box to import the file and most clients are standard comma delimited .txt files.
Private Sub Command38_Click()
Dim f As Object
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
Dim strFile As String
Dim strFolder As String
Dim varItem As Variant
Dim P As String
Dim DeleteEverything As String
DoCmd.SetWarnings False
DeleteEverything = "DELETE * FROM [tcppltr]"
DoCmd.RunSQL DeleteEverything
Set f = Application.FileDialog(3)
f.AllowMultiSelect = True
f.InitialFileName = "G:\access\TCPP\"
f.Filters.Clear
f.Filters.Add " Armored TXT Files", "*.asc"
If f.Show Then
For Each varItem In f.SelectedItems
strFile = Dir(varItem)
strFolder = Left(varItem, Len(varItem) - Len(strFile))
P = strFolder & strFile
DoCmd.TransferText acImportDelim, "TCPP Import Specification", "tcppltr", P, False
Next
End If
End Sub
My first idea was to just have the mail merge print a duplicate of the first record which would be better as we don't need duplicates of the shipping labels and everything else that will come from this record but I wasn't sure there was even a way to do that only for the mail merge without creating a separate table with the duplicate record for use only with the mail merge. That seemed terribly inefficient in my opinion.
I am open to other suggestions on how to do this besides just duplicating a record on import.
Thanks in advance for everyone's time and help in this matter!
What this basically does is open two recordsets. The first recordset points to the record you want to duplicate (in this case I did a MoveFirst you can specifically pick whichever record or modify this code to duplicate multiple records). Currently this only copies 1 record.
Dim db As Database
Dim rs1 As Recordset, rs2 As Recordset
Dim i As Long
Set db = CurrentDb
Set rs1 = db.OpenRecordset("Table1", dbOpenSnapshot)
Set rs2 = db.OpenRecordset("Table1", dbOpenDynaset)
rs1.MoveFirst
rs2.AddNew
For i = 1 To rs2.Fields.Count - 1
rs2.Fields(i) = rs1.Fields(i)
Next
rs2.Update
rs1.Close
rs2.Close
If you want an SQL solution I think you need to know before hand the names of all the fields and use an SELECT and INSERT

Storing and recreating relations in Access

I'm wondering if it is possible to use VBA to store, delete and recreate relationships on tables in Access VBA? The deletion part is easy, but how to store it in such a way as to be able to restore it after it's been deleted is where I get stuck.
I originally wanted to know so that I could bulk copy certain tables from one database into another copy of that database. I ran into trouble as the ref. integrity on the tables was interfering with the inserts. I thought about trying to store then delete the relations, insert the data, then restore the relations using DAO.
After thinking about it and trying to come up with some code for it, I abandoned the idea and inserted it in a different way to avoid the issue altogether. However, after the fact, I was pondering if what I had been trying is doable.
Any thoughts?
EDIT: Here's the code I started to write.
Private Sub Save_Click()
Dim db As DAO.Database
Set db = CurrentDb
'Save db.Relations somehow as SavedRelations
End Sub
Private Sub Delete_Click()
Dim db As DAO.Database
Dim rel As DAO.Relation
Set db = CurrentDb
For Each rel In db.Relations
db.Relations.Delete (rel.Name)
Next
End Sub
Private Sub Restore_Click()
Dim db As DAO.Database
Dim rel As DAO.Relation
Dim newRel As DAO.Relation
For Each rel In SavedRelations 'Stored relations from the Save sub
Set newRel = db.CreateRelation(rel.Name, rel.table, rel.ForeignTable, rel.Attributes)
For Each fld In rel.Fields
newRel.Fields.Append fld
Next
db.Relations.Append newRel
Next
End Sub
If you make a backup copy of your database before you delete the relations, you can copy them back later.
Private Sub Restore_Click()
Dim db As DAO.Database
Dim dbBackup As DAO.Database
Dim rel As DAO.Relation
Dim newRel As DAO.Relation
Set db = CurrentDb()
Set dbBackup = OpenDatabase("C:\temp\backup.mdb")
For Each rel In dbBackup.Relations
Set newRel = db.CreateRelation(rel.Name, rel.table, rel.ForeignTable, _
rel.Attributes)
For Each fld In rel.Fields
newRel.Fields.Append newRel.CreateField(fld.Name)
newRel.Fields(fld.Name).ForeignName = _
rel.Fields(fld.Name).ForeignName
Next fld
db.Relations.Append newRel
Next rel
Set fld = Nothing
Set rel = Nothing
Set dbBackup = Nothing
Set db = Nothing
End Sub
The following code will create a classic parent to child relationship
Dim nRel As DAO.Relation
Dim db As DAO.Database
Set db = CurrentDb
Set nR = db.CreateRelation("ContactIDRI", "tblContacts", _
"tblChildren", dbRelationDeleteCascade + dbRelationLeft)
nR.Fields.Append nR.CreateField("ContactID") ' parent table PK
nR.Fields("ContactID").ForeignName = "Contact_ID" ' child table FK
db.Relations.Append nR
db.Relations.Refresh
Nice work HansUp!
I modified it slightly to allow for a late-binding file browser.
Sorry guys ... it took me a few edits to get the hang of these "code block" instructions. Hopefully it's right now:(
Function selectFile()
'Late binding version of selectFile
'No MS Office Object references needed
'''''''''''''''''''''''''''''''''''''''
'http://www.minnesotaithub.com/2015/11/solved-late-binding-file-dialog-vba-example/
Dim fd As Object
Set fd = Application.FileDialog(3)
With fd
If .Show Then
selectFile = .SelectedItems(1)
Else
End
End If
End With
Set fd = Nothing
End Function
Public Function fRestoreRelationships()
'http://stackoverflow.com/questions/4028672/storing-and-recreating-relations-in-access
Dim db As DAO.Database
Dim dbBackup As DAO.Database
Dim rel As DAO.Relation
Dim newRel As DAO.Relation
Dim strBackupPath As String
Dim Msg As String
Dim CR As String
CR = vbCrLf
Msg = ""
Msg = Msg & "This procedure restores the relationships from a previous backup." & CR & CR
Msg = Msg & "If you would like to proceed with this operation, " & CR
Msg = Msg & "Please click on the [OK] button " & CR
Msg = Msg & "Otherwise click [Cancel] to exit this pocedure."
If MsgBox(Msg, vbOKCancel, "Proceed?") = vbOK Then
strBackupPath = selectFile 'Calls a FileBrowser Dialog and returns a string value
Set db = CurrentDb()
Set dbBackup = OpenDatabase(strBackupPath)
For Each rel In dbBackup.Relations
Set newRel = db.CreateRelation(rel.Name, rel.Table, rel.ForeignTable, _
rel.Attributes)
For Each fld In rel.Fields
newRel.Fields.Append newRel.CreateField(fld.Name)
newRel.Fields(fld.Name).ForeignName = _
rel.Fields(fld.Name).ForeignName
Next fld
db.Relations.Append newRel
Next rel
End If
Set fld = Nothing
Set rel = Nothing
Set dbBackup = Nothing
Set db = Nothing
End Function

Select a value from a table in current DB and use a variable in Access VBA

In Access VBA, I want to use values from a "Settings" table, instead of hard-coding folder locations etc. in the code. I can't figure out how to load a value from the table and use it in the code.
Dim oFSystem As Object
Dim oFolder As Object
Dim oFile As Object
Dim sFolderPath As String
sFolderPath = "C:\Documents and Settings\Main\Desktop\Files" 'BAD BAD, I WANT TO AVOID THIS
I have created a table "Settings", and I want to use the value
SELECT TOP 1 Settings.SettingsValue FROM Settings WHERE (((Settings.SettingName)="Files Folder Location"));
You could use the DLookup function if you have only one record where SettingName="Files Folder Location".
sFolderPath = DLookup("SettingsValue", "Settings", "SettingName=""Files Folder Location""")
One way:
Dim db As DAO.Database
Dim rs1 As DAO.Recordset
Dim sFolderPath As String
Set db = CurrentDb()
Set rs1 = db.OpenRecordset("SELECT TOP 1 SettingsValue FROM Settings WHERE SettingName="Files Folder Location")
If rs1.RecordCount > 0 Then
rs1.MoveFirst
sFolderPath = rs1.Fields("SettingsValue")
End If
rs1.Close
set rs1 = Nothing
set db = Nothing

MS ACCESS 2007 VBA : DAO recordset....how can I view all the "fields" in the returned collection

so if i do a SQL statement like so:
sql = "SELECT * FROM tblMain"
set rs = currentdb.openrecordset(sql)
what method can i use to view every "field name" in this collection i have just created. i am getting some very strange error stating that the item is not found in this collection.
i know the field exists in the table, i have triple checked the spelling everywhere when i reference it, and the SQL should be pulling everything, but i want to see it.
is there a debug.print method to see all these fields
thanks
Justin
This is a variation on the other answers, but I believe it's better to use a For/Each loop than a counter:
Dim rs As DAO.Recordset
Dim fld As DAO.Field
Set rs = CurrentDB.OpenRecordset("SELECT * FROM tblMain")
For Each fld In rs.Fields
Debug.Print fld.Name
Next fld
Set fld = Nothing
rs.Close
Set rs = Nothing
You can iterate through the fields collection of the recordset.
Code is OTTOMH
Dim NumFields as Integer
For NumFields = 0 to rs.Fields.Count -1
Debug.Print Rs.Fields(NumFields).Name
Next
Alternately, you can set a breakpoint at set rs = currentdb.openrecordset(sql) and then as soon as the statement executes, right-click on rs, choose add watch and view the whole thing in the Watches window.
Here is a script that will look for a field containing the string you specify in every table in an Access database (except System and Attached Tables) and write it to text files:
Option Compare Database
Option Explicit
Sub main()
Dim db As Database
Dim rs As Recordset
Dim bFinished As Boolean
Dim sFieldName As String
Dim iPosition, z, x As Integer
Dim bRetVal As Boolean
Dim tdTemp As TableDef
Dim iDatabaseNumbers As Integer
Const FIELD_TO_FIND = "FieldName"
Set db = CurrentDb
Open Left(db.Name, Len(db.Name) - 4) & "_" & FIELD_TO_FIND & ".txt" For Output As #1
For x = 0 To db.TableDefs.Count - 1
Set tdTemp = db.TableDefs(x)
bRetVal = IIf(tdTemp.Attributes And dbSystemObject, False, True)
If bRetVal Then
bRetVal = IIf(tdTemp.Attributes And dbAttachedTable, False, True)
End If
If bRetVal Then
Set rs = db.OpenRecordset(db.TableDefs(x).Name)
If rs.RecordCount > 0 Then
For z = 0 To rs.Fields.Count - 1
sFieldName = rs.Fields(z).Name
If InStr(1, sFieldName, FIELD_TO_FIND, vbTextCompare) > 0 Then
Print #1, db.TableDefs(x).Name
Exit For
End If
Next z
End If
End If
Next x
Close #1
MsgBox "Done"
End Sub
You could adjust accordingly to make it do what you need.