Rewrite field names in multiple tables - skipping over missing fields - ms-access

I have an Access database with nearly 200 tables each with about 150 field. I need to change most of the field names and am writing some VBA code to programatically update the names to what I assign. The problem is that not all tables have exactly the same fields (some fields are missing from certain tables). Is there a way that I can write the change in the code, but just skip the change for a particular field if it doesn't exist in a particular table?
The basic code that I am using comes from this site: http://windowssecrets.com/forums/showthread.php/125845-Change-Field-name-in-Table-with-VBA
And here is my actual code. I'm brand new to VBA, so please be gentle.
Option Compare Database
Option Explicit
Public Sub changeFieldName()
Dim db As DAO.Database
Dim table As DAO.TableDef
Set db = CurrentDb
For
Set table = db.TableDefs("table")
table.Fields("Field1").Name = "name1"
table.Fields("Field2").Name = "name2"
if(IsNull(table.Fields("FieldDoesn'tExist").Name = "name")) Then End If
Set table = Nothing
Next
db.Close
Set db = Nothing
MsgBox "Changed"
End Sub
The "Then End If" statement doesn't work, but I don't know what to use here
Thanks for any help!
Paul

The way I'd approach it would be to put the old and new names into their own table named [NameMap]:
oldName newName
-------- --------
oldName1 newName1
oldName2 newName2
and then loop through that list to apply the name changes. The On Error Resume Next statement would allow the routine to continue if the table did not have a field whose name corresponded to one of the [oldName] values
Option Compare Database
Option Explicit
Public Sub changeFieldNames()
Dim cdb As DAO.Database, rst As DAO.Recordset, tbd As DAO.TableDef
Set cdb = CurrentDb
Set tbd = cdb.TableDefs("SampleTable")
Set rst = cdb.OpenRecordset("SELECT oldName, newName FROM NameMap", dbOpenSnapshot)
Do Until rst.EOF
On Error Resume Next
tbd.Fields(rst!oldName).Name = rst!newName
On Error GoTo 0
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
Set tbd = Nothing
Set cdb = Nothing
End Sub

Related

VBA Access Object Type Returned For Combobox Field

How can I iterate a record set that returns a field of type field2?
Is there a way to tell how many objects are in the field2 type?
Let me describe the relevant aspects of my table:
The table fields has field NMR which contains a list of possible options a user can select in another table. In the Experiments table, the field NMR is a combobox with populates the options from the other table.
The way I do this is in the Experiments table design, I have set the field this way:
Now in one of my forms, I need to read the value in Experiments!NMR which can be a multiple selections allowed combobox. The recordset rs!NMR is of type Field2.
To get the values, you iterate using an integer (i.e. rs!NMR(0) would return the first selected option). The problem is I don't know how to get the field count and calling !NMR(i) where i is greater than the number of elements will invoke a Run time error '3265', Object doesn't exist in this collection.
Their exist a size method only returns the field width size (4?) and the documentation states this is the size of the data type within the field2 object.
There doesn't seem to be a count method associated with field2 as using !NMR.Count invokes runtime error 438, Object doesn't support this method.
Code:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim qry As String
qry = "SELECT * FROM Experiments"
Set db = CurrentDb
Set rs = db.OpenRecordset(qry, dbOpenSnapshot)
With rs
Do While Not .EOF
Dim i As Integer
For i = 0 to !NMR.Count ' or SOMETHING - this is the problem
' this is irrelevant, I need to know how to iterate the list
Next i
.MoveNext
Loop
End With
rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
I've also tried logic control such as
Do While(!NMR(i) <> vbNullString) since the individual components are strings, but no luck. This issues the same 3265: Item isn't found error. Same for a loop with this check Do While Not IsNull(!NMR(i))
Is there a way to tell how many objects are in the Field !NMR?
You need to assign the complex Field2 to a Recordset2 object and loop through it.
Sub Whatever()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim rsComplex As DAO.Recordset2
Dim qry As String
qry = "SELECT * FROM Experiments"
Set db = CurrentDb
Set rs = db.OpenRecordset(qry, dbOpenSnapshot)
Do While Not rs.EOF
Set rsComplex = rs("NMR").Value
rsComplex.MoveLast
rsComplex.MoveFirst
Dim i As Integer
For i = 0 To rsComplex.RecordCount - 1 ' Asker modified
Debug.Print rsComplex(0)
rsComplex.MoveNext
Next i
rsComplex.Close
Set rsComplex = Nothing
rs.MoveNext
Loop
rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
End Sub

Advanced Filter Criteria in Access

The issue is simple but I just cant figure it out.
I have two tables in access, one with records and another with "key words". I need to filter the records containing certain "key words". In other words, use one table field as a filter criteria for the other, but without linking them because the "key words" table just contains random words instead of a whole record.
In excel I can run an advanced filter on my records and just specify as criteria the list of key words (and using wildcards), but in acces I havent found a way to filter according to another table fields.
Any ideas about it?
You may need to create a function that spits out custom SQL with all the keywords in it. Here is an example to get you started.
Public Function fGetTrashRecords()
'add your own error handling
Dim SQL As String
Dim rst As DAO.Recordset
Dim rstTrash As DAO.Recordset
Dim db As DAO.Database
Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT sKeyWord FROM tblBadKeyWords", dbOpenSnapshot)
If Not rst Is Nothing Then
rst.MoveFirst
Do While Not rst.EOF
SQL = SQL & " strFieldContaingKeyWord LIKE *'" & rst!sKeyWord & "'* OR"
rst.MoveNext
Loop
If SQL > "" Then SQL = Left(SQL, Len(SQL) - 2) 'get rid of the last OR
rst.Close
Set rst = Nothing
End If
If SQL > "" Then
Set rstTrash = db.OpenRecordset("SELECT * FROM tblHasKeyWords WHERE " & SQL, dbOpenDynaset, dbSeeChanges)
If Not rstTrash Is Nothing Then
rstTrash.MoveFirst
Do While Not rstTrash.EOF
Debug.Print rstTrash!ID
rstTrash.MoveNext
Loop
rstTrash.Close
Set rstTrash = Nothing
End If
End If
Set db = Nothing
End Function

Accessing all records in a field

Just started using VBA and I'm trying to access all the data in a dummy table I set up called Employees.
This is the code im trying:
Sub getRecords()
Dim dbs As Database
Dim rst As Recordset
Dim sql As String
Set dbs = CurrentDb
sql = "SELECT * FROM Employees"
Set rst = dbs.OpenRecordset(sql)
End Sub
The ultimate aim here is to print the contents to the screen — would this involve breaking down the record set into different components? If so what components could make up a typical record set?
The table format is as follows:
Emp_Id - Number
Emp_Name - Text
Emp_Email - Text
You can iterate through the fields:
Sub getRecords()
Dim dbs As Database
Dim rst As Recordset
Dim sql As String
Set dbs = CurrentDb
sql = "SELECT * FROM Employees"
Set rst = dbs.OpenRecordset(sql)
Do while not rst.eof
For each fld in rst.Fields
Debug.Print fld, fld.name
Next
rst.MoveNext
''You can also edit or add
rst.Edit
rst!Emp_Name = "Something"
rst.UpDate
Loop
End Sub
I would avoid calling variables names that are also properties, such as SQL.
For updates, you are usually best to use an Action query and Execute againt a database object:
db.Execute "UPDATE aTable SET aField = 'Some text'", dbFailOnError
You'll need to start by looping through the records. Try:
Do While Not rst.EOF And Not rst.BOF
...
Loop
To do that. BOF and EOF relate to the beginning and end of the recordset respectively. If there's no data in the table then the whole loop will be skipped.
From there you can look at the fields individually by either using an index to relate to the position of the field in the select list, or by referring to the field name, like so:
Do While Not rst.EOF And Not rst.BOF
Debug.Print rst.Fields("myfield")
Debug.Print rst.Fields(0)
Loop
That's a starting point. Intelisense should really help you with this.
PS: always remember to close your recordset objects afterward to reclaim the memory:
rst.Close()
Set rst = Nothing
Kind regards,
Paul.

Issue using Access DoCmd.Rename on table: linked names not renamed

Summary: why might Docmd.Rename on a table result in tables that don't change name over a Link from another DB?
I'm trying to fix up an old database that needs TLC. Part of this is deleting lots of unused cruft, amongst which are some tables. The first part if a VBA procedure that calls DoCmd.Rename on these tables, renaming with DELETE_ prepended.
The "deletes" appear to work fine - but when I try to reference tables from another DB using the Linked Table manager, no renames have happened at all. If I go back and load that DB, the table names are changed.
Is it best to use TableDefs().Name to rename? Is that a better method? I'd assumed an "official" way like Rename would be better.
I'm using Access 2007 on Win7/64. The files are in MDB format.
Do you wish to rename the tables in the linked database? If so, you can use OpenDatabase to reference the linked Access database. You might try something on the lines of:
Dim dbLink As DAO.Database
Dim dbCurr As DAO.Database
Dim ws As DAO.Workspace
Dim rst As DAO.Recordset
Dim tdf As TableDef
Set ws = DBEngine.Workspaces(0)
Set dbCurr = CurrentDb
For Each tdf In dbCurr.TableDefs
sConn = tdf.Connect
sSource = tdf.SourceTableName
sName = tdf.Name
If InStr(sConn, ";DATABASE=") > 0 Then
strdb = Mid(sConn, InStr(sConn, ";DATABASE=") + 10)
If InStr(sConn, "PWD") > 0 Then
sPWD = Left(sConn, InStr(sConn, ";DATABASE="))
Else
sPWD = vbNullString
End If
If Dir(strdb) <> vbNullString Then
Set dbLink = ws.OpenDatabase(strdb, False, False, sPWD)
dbLink.TableDefs(sSource).Name = "DELETE_" & sSource
End If
End If
Next

Code To Loop Through and Edit Recordsets

I have found how to loop through recordsets with the following link:
Code to loop through all records in MS Access
However, I want to know if it is possible if I can remove a record from the recordset if it doesn't meet criteria that I specify in the loop.
EDIT
I am now getting an error with the following code:
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("fieldHistory", dbOpenTable)
where fieldHistory is the name of the query recordset I want to open. Why am I getting this error? The last line of code there is the source of the error and Access simply states "Invalid operation"
Yes, you can use the DAO recordset's Delete method to delete the current record. This example will delete rows where the fname value is "xxx".
Public Sub DeleteRecordsetRow()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("tblDiscardMe", dbOpenTable)
Do While Not rs.EOF
If rs!fname = "xxx" Then
rs.Delete
'* the next line would trigger *'
'* error 3167: "Record is deleted." *'
''Debug.Print rs!fname
End If
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
Notice that immediately after rs.Delete (i.e. before MoveNext), the deleted row is still "current", but you can't access its values. You can uncomment the Debug.Print line to examine this further.
Edit:
Since your record source is a query rather than a table, try this to narrow down the reason you're getting an error with OpenRecordset.
Public Sub foo20110527a()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("fieldHistory")
If Not (rs.BOF And rs.EOF) Then
rs.MoveLast
MsgBox "RecordCount: " & rs.RecordCount
Else
MsgBox "No records"
End If
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
Since you used English (rather than English-like technical terms), your intent isn't very clear. You ask if you can "...remove a record...", which can mean either that you want to Delete it (in which case you already have a good answer form HansUp), or that you want to filter it out so that you don't see it, while leaving it in the underlying database.
If your intent is the latter (filtering), you have two choices:
Use a SQL statement with a WHERE clause in the original OpenRecordset call.
Use the Recordset's .Filter property before you enter the loop.
Access comes with adequate (if not stellar) Help on either topic.