Mass replace accross tables (1 Viewer)

Lanason

Registered User.
Local time
Today, 08:21
Joined
Sep 12, 2003
Messages
258
Morning people of the Access World.

I have a need to do a "Mass replace" to remove personal detail from a number of tables. For example:- I want to change all instances of the Name "Joe Smith" to "xyz"

I need to do this across all my tables. Does anyone have a routine that can interrogate all tables in a DB and then all fields to search and replace??

Thanks in advance :confused:
 

Cronk

Registered User.
Local time
Today, 17:21
Joined
Jul 4, 2013
Messages
2,774
How many tables do you have people data? I think I might have had as many as three say tblEmployees, tblCustomers, tblSuppliers and in most cases I'd be looking to combine the three into one, depending on the field structure.

In any case, it is only an update query for each table.
 

Lightwave

Ad astra
Local time
Today, 08:21
Joined
Sep 27, 2004
Messages
1,521
I did a quick tinternet search and came back with this. I would probably create a table to hold all the field names in and with the recordset write the table names to the table.

Code:
Public Functions ShowTableFields()

Dim db As Database
Dim tdf As TableDef
Dim x As Integer

Set db = CurrentDb

For Each tdf In db.TableDefs
   If Left(tdf.Name, 4) <> "MSys" Then ' Don't enumerate the system tables
      For x = 0 To tdf.Fields.Count - 1
      Debug.Print tdf.Name & "','" & tdf.Fields(x).Name
      Next x
   End If
Next tdf
End Sub

and my altered version (written but NOT tested)
create a table called TableofFieldNames with fields
strTable
strFieldName

Copy and paste the below to a module and then within the vba editor go to view Immediate window and then type ?ShowTableFields

Code:
Public Functions ShowTableFields()

Dim db As DAO.Database
Dim tdf As TableDef
Dim x As Integer
Dim rs as DAO.Recordset

Set db = CurrentDb
Set db.OpenRecordset("TableofFieldNames")

For Each tdf In db.TableDefs
   If Left(tdf.Name, 4) <> "MSys" Then ' Don't enumerate the system tables
      For x = 0 To tdf.Fields.Count - 1
      ' Comment OUT Debug.Print tdf.Name & "','" & tdf.Fields(x).Name
      
      With rs
      rs.addnew
      rs!strTable = tdf.Name
      rs!strFieldName = tdf.Fields(x).Name
      rs.Update
      End With

Next x
   End If
Next tdf

set rs = nothing
set db = nothing
End Function
 
Last edited:

Lightwave

Ad astra
Local time
Today, 08:21
Joined
Sep 27, 2004
Messages
1,521
and here's a function to randomise a field if you need it - not sure if this randomises two records of the same string the same or differently .

I guess you might want to test that. (Looking at its use of the Rnd Function I think they might be different which may make it unsuitable)

Code:
Public Function ScrambleID(parmString) As String

Dim lngLoop As Long
Const cAlpha As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Const cNum As String = "0123456789"
Dim strNewChar As String
Dim strThisChar As String

   For lngLoop = 1 To Len(parmString)
   strThisChar = Mid$(parmString, lngLoop, 1)
   Do
        Select Case strThisChar
            Case "A" To "Z"
            strNewChar = Mid$(cAlpha, Int(Rnd * Len(cAlpha)) + 1, 1)
            Case "0" To "9"
            strNewChar = Mid$(cNum, Int(Rnd * Len(cNum)) + 1, 1)
       End Select
   Loop While strNewChar = strThisChar
   ScrambleID = ScrambleID & strNewChar
   Next
End Function
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 15:21
Joined
May 7, 2009
Messages
19,246
you try this, paste it in new module.
it will loop through all tables and
replace all fields where SearchString is found,
with ReplacementString.
Code:
'you try this, paste it in new module.
it will loop through all tables and
replace all fields where SearchString is found,
with ReplacementString.
[code]
Public Function ReplaceAnyField(SearchString As String, ReplacementString As String)
    Dim td As DAO.TableDef
    Dim db As DAO.Database
    Dim strAction As String
    Dim fld As DAO.Field
    Dim arrFields As Variant
    Dim strField As String
    Dim lngCount As Long
    Dim strTable As String
    Dim var As Variant
    
    Set db = CurrentDb
    
    For Each td In db.TableDefs
        strField = ""
        If InStr(td.Name, "~") = 0 And InStr(td.Name, "Msys") = 0 Then
            strTable = "[" & td.Name & "]"
            For Each fld In td.Fields
                lngCount = DCount("[" & fld.Name & "]", strTable, _
                        "instr([" & fld.Name & "]," & Chr(34) & SearchString & Chr(34) & ")>0")
                If lngCount > 0 Then _
                    strField = strField & ",[" & fld.Name & "]"
            Next
        End If
        If strField <> "" Then
            strAction = ""
            arrFields = Split(Mid(strField, 2), ",")
            For Each var In arrFields
                strAction = "Update " & strTable & " Set " & var & "=Replace(" & var & "," & Chr(34) & SearchString & Chr(34) & "," & Chr(34) & ReplacementString & Chr(34) & ")" & _
                " Where InStr(" & var & "," & Chr(34) & SearchString & Chr(34) & ")>0"
            Next
            
            db.Execute strAction
        End If
    Next
    Set db = Nothing
End Function



just call it:

Call ReplaceAnyField("oldString","newString")
 
Last edited:

Lanason

Registered User.
Local time
Today, 08:21
Joined
Sep 12, 2003
Messages
258
Just trying this code now

Private Sub Command0_Click()

Call ReplaceAnyField("Pink", "****PINK****")

End Sub

but I get the error ...
"Argument not optional"
 

jdraw

Super Moderator
Staff member
Local time
Today, 03:21
Joined
Jan 23, 2006
Messages
15,394
Adrian,
"to remove personal detail from a number of tables."
For clarity, do you want to replace all string values with a new value?
For all tables where a field has text datatype make random replacements?
Or do you want to replace all instances of Name -where name = "Joe Smith" - to "xyz"

A little more detail to get the proper "requirement" would be helpful.
 

Lightwave

Ad astra
Local time
Today, 08:21
Joined
Sep 27, 2004
Messages
1,521
Just a hunch but don't use * in the replace string. The code builds an SQL updated query and * is seen as a wild card which will do something very weird probably in an update query.

How about change PINK to BLUE
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 02:21
Joined
Feb 28, 2001
Messages
27,303
Let's ask one question before you go off into the night.

Are any of the fields Primary Keys for which a child table uses them as a Foreign Key? If so, you might have a tougher road ahead of you. I'll avoid the tedium until you reply that you have this case.
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 15:21
Joined
May 7, 2009
Messages
19,246
Search for fnAnySQL on this forum.
Copy and paste it in a standard module.
Then replace this part of code:
Code:
 If strField <> "" Then
            strAction = ""
            arrFields = Split(Mid(strField, 2), ",")
            For Each var In arrFields
                strAction = "Update " & strTable & " Set " & var & "=Replace(" & var & "," & Chr(34) & SearchString & Chr(34) & "," & Chr(34) & ReplacementString & Chr(34) & ")" & _
                " Where InStr(" & var & "," & Chr(34) & SearchString & Chr(34) & ")>0"
            Next
            
            db.Execute strAction
        End If

With this:

Code:
      If strField <> "" Then
            strAction = ""
            arrFields = Split(Mid(strField, 2), ",")
            For Each var In arrFields
                strAction = "Update " & strTable & " Set " & var & "=Replace(" & var & ", @1, @2)" & _
 " Where InStr(" & var & ", @1)>0"
        Call fnAnySQL(strAction, SearchString, ReplacementString)
            Next
            
            
        End If
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 15:21
Joined
May 7, 2009
Messages
19,246
here i replaced the function.
I included fnAnySQL() function.
Code:
''
'' arnelgp
''
'' purpose
''
'' replace old string with new string on all table on all fields
''
''
'' parameters
''
'' SearchString     =   the string you want to be replaced
'' ReplacementString    =   of course, the new string replacement
''
''
'' calls    fnAnySQL() function
''
Option Compare Database
Option Explicit

Public Function ReplaceAnyField(SearchString As String, ReplacementString As String)
    Dim td As DAO.TableDef
    Dim db As DAO.Database
    Dim strAction As String
    Dim fld As DAO.Field
    Dim arrFields As Variant
    Dim strField As String
    Dim lngCount As Long
    Dim strTable As String
    Dim var As Variant
    
    Set db = CurrentDb
    DoCmd.Hourglass True
    For Each td In db.TableDefs
        strField = ""
        If InStr(td.Name, "~") = 0 And InStr(td.Name, "Msys") = 0 Then
            strTable = "[" & td.Name & "]"
            For Each fld In td.Fields
                'only fields that are not multivalues are included
                If fld.type < 101 Then
                    lngCount = DCount("[" & fld.Name & "]", strTable, _
                            "instr([" & fld.Name & "]," & Chr(34) & SearchString & Chr(34) & ")>0")
                    If lngCount > 0 Then _
                        strField = strField & ",[" & fld.Name & "]"
                End If
            Next
        End If
        If strField <> "" Then
            strAction = ""
            arrFields = Split(Mid(strField, 2), ",")
            For Each var In arrFields
                strAction = "Update " & strTable & " Set " & var & "=Replace(" & var & ", @p1, @p2)" & _
                " Where InStr(" & var & ", @p1)>0"
                
                Call fnAnySQL(strAction, SearchString, ReplacementString)
                DoEvents
            Next
            
        End If
        DoEvents
    Next
    Set db = Nothing
    DoCmd.Hourglass False
End Function


Public Function fnAnySQL(ByVal strSQL As String, ParamArray p() As Variant)
'
' strSQL must be an Any SQL statement (Select, Insert, Update, Delete)
' parameters should be in format @1, @2, ... to be
' consistent
'
' DO NOT use parameter name which has same name as your fieldname.
' using this will take the fieldname instead of the parameter.
'
' Example:
'
' SELECT Statement:
'   Dim rs As DAO.Recordset
'   set rs = fnAnySQL("SELECT field1 FROM table1 WHERE Names = @1;", "arnelgp")
'
'
' UPDATE Statement:
'   Call fnAnySQL("Update table1 Set field1 = @1;", "arnelgp")
'
'
' DELETE Statement:
'   Call fnAnySQL("Delete table1.* From table1 Where field1 = @1;", "arnelgp")
'
' INSERT Statement:
'   Call fnAnySQL("Insert Into table1 (field1, field2) SELECT @1, @2;", "arnel", "gp")
'
'
    Dim param As Parameter
    Dim i As Integer
    With CurrentDb.CreateQueryDef("", strSQL)
        For i = 0 To .Parameters.Count - 1
            .Parameters(i) = p(i)
        Next
        If InStr(strSQL, "SELECT") = 1 And InStr(strSQL, "INTO") = 0 Then
            ' Simple select query and not Create table query
            Set fnAnySQL = .OpenRecordset(dbOpenDynaset)
        Else
            ' Action queries
            .Execute (dbFailOnError)
        End If
    End With
            
End Function
 

Lanason

Registered User.
Local time
Today, 08:21
Joined
Sep 12, 2003
Messages
258
Thanks all could indeed be the ****

I was just using is as a text example for the test before I included in my main database - let me try and see
 

Lanason

Registered User.
Local time
Today, 08:21
Joined
Sep 12, 2003
Messages
258
Yes the **** was the issue
the odd thing is though that if the text is in more than one field in the same record - it only fixes one of them.
If I run the code again it fixes the other.
so it looks like it only does one "instance" per record . . . would that be expected?
and how can I modify to do multiple fields?
 

Cronk

Registered User.
Local time
Today, 17:21
Joined
Jul 4, 2013
Messages
2,774
Re #6, the error is probably because
call Call ReplaceAnyField("Pink", "****PINK****")
gives an error because ReplaceAnyField is a function, not a subroutine.

Change it to
Sub ReplaceAnyField(...,...)
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 15:21
Joined
May 7, 2009
Messages
19,246
It can now handle memo field.
Code:
''
'' arnelgp
''
'' purpose
''
'' replace old string with new string on all table on all fields
''
''
'' parameters
''
'' SearchString     =   the string you want to be replaced
'' ReplacementString    =   of course, the new string replacement
''
''
'' calls    fnAnySQL() function
''
Option Compare Database
Option Explicit

Public Function ReplaceAnyField(SearchString As String, ReplacementString As String, Optional ExactMatch As Boolean = False)
    Dim td As DAO.TableDef
    Dim db As DAO.Database
    Dim strAction As String
    Dim fld As DAO.Field
    Dim arrFields As Variant
    Dim strField As String
    Dim lngCount As Long
    Dim strTable As String
    Dim var As Variant
    Dim strCriteria As String
    
    Set db = CurrentDb
    DoCmd.Hourglass True
    For Each td In db.TableDefs
        strField = ""
        If InStr(td.Name, "~") = 0 And InStr(td.Name, "Msys") = 0 Then
            strTable = "[" & td.Name & "]"
            For Each fld In td.Fields
                'only fields that are not multivalues are included
                'and don't include date field and memo field.
                If fld.type < 101 And fld.type <> dbDate Then
                    If ExactMatch Then
                        strCriteria = "[" & fld.Name & "]=" & Chr(34) & SearchString & Chr(34)
                    Else
                        strCriteria = "instr([" & fld.Name & "]," & Chr(34) & SearchString & Chr(34) & ")>0"
                    End If
                    lngCount = DCount("[" & fld.Name & "]", strTable, _
                            strCriteria)
                    If lngCount > 0 Then
                        '' if this is a memo field, we cannot use Replace() to it
                        '' we need to put the memo into a variable,
                        '' manipulate the variable, then put the modified
                        '' memo back
                        If fld.type = dbMemo Then
                            Call fnReplaceMemo(strTable, fld.Name, SearchString, ReplacementString)
                        Else
                            strField = strField & ",[" & fld.Name & "]"
                        End If
                    End If
                End If
            Next
        End If
        If strField <> "" Then
            strAction = ""
            arrFields = Split(Mid(strField, 2), ",")
            For Each var In arrFields
                '' loop through all fields where SearchString is found.
                If ExactMatch Then
                    strAction = "Update " & strTable & " Set " & var & "=@p2" & _
                    " Where " & var & "=@p1"
                Else
                    strAction = "Update " & strTable & " Set " & var & "=Replace(" & var & ", @p1, @p2)" & _
                    " Where InStr(" & var & ", @p1)>0"
                End If
                Call fnAnySQL(strAction, SearchString, ReplacementString)
                DoEvents
            Next
            
        End If
        DoEvents
    Next
    Set db = Nothing
    DoCmd.Hourglass False
End Function


Private Function fnReplaceMemo(tableName As String, Memo As String, search As String, replacement As String)
    Dim rs As DAO.recordSet
    Dim strMemo As Variant
    Set rs = CurrentDb.OpenRecordset("select [" & Memo & "] from " & tableName, dbOpenDynaset)
    With rs
        .MoveFirst
        While Not .EOF
            strMemo = rs(0).Value
            If Not IsNull(strMemo) Then
                strMemo = replace(strMemo, search, replacement)
                .Edit
                    .Fields(Memo) = strMemo
                .Update
            End If
            .MoveNext
            DoEvents
        Wend
        .Close
    End With
    Set rs = Nothing
End Function
 

Lanason

Registered User.
Local time
Today, 08:21
Joined
Sep 12, 2003
Messages
258
Thank arnelgp - after a bit of tweeking it worked great and I ran a number of times with great success.

However, now I have the error "operation must use an updateable query"

any ideas?:confused:
 

Lanason

Registered User.
Local time
Today, 08:21
Joined
Sep 12, 2003
Messages
258
Ha ha I've worked it out - it is because the data is in an attached EXCEL spreadsheet . .. now deleted

is there a way that spreadsheets can be excluded from the search??
 

arnelgp

..forever waiting... waiting for jellybean!
Local time
Today, 15:21
Joined
May 7, 2009
Messages
19,246
add code to check the tabledef's Connection if ".xls" can be found:

If Instr(td.Connection, ".xls") <> 0 then
' don't include it
End If
 

Users who are viewing this thread

Top Bottom