views:

1180

answers:

4

I have a couple of mdb files with the exact table structure. I have to change the primary key of the main table from autonumber to number in all of them, which means I have to:

  1. Drop the all the relationships the main table has
  2. Change the main table
  3. Create the relationships again,... for all the tables.

Is there any way to export the relationships from one file and importing them to all the rest?

I am sure this can be done with some macro/vb code. Does anyone has an example I could use?

Thanks.

+6  A: 

Not a complete solution, but this may get you going...

The following function will print out the metadata for all relationships. Change this to save to a file in whatever format you prefer (CSV, tab delimited, XML, etc.):

Function PrintRelationships()
    For Each rel In CurrentDb.Relations
        With rel
            Debug.Print "Name: " & .Name
            Debug.Print "Attributes: " & .Attributes
            Debug.Print "Table: " & .Table
            Debug.Print "ForeignTable: " & .ForeignTable

            Debug.Print "Fields:"
            For Each fld In .Fields
                Debug.Print "Field: " & fld.Name
            Next
        End With
    Next
End Function

This function will drop all the relationships in the database:

Function DropRelationships()
    With CurrentDb
        For Each rel In .Relations
            .Relations.Delete Name:=rel.Name
        Next
    End With
End Function

This function will create a relationship. You'll have to iterate over the file of saved relationship data.

Function CreateRelationships()
    With CurrentDb
        Set rel = .CreateRelation(Name:="[rel.Name]", Table:="[rel.Table]", ForeignTable:="[rel.FireignTable]", Attributes:=[rel.Attributes])
        rel.Fields.Append rel.CreateField("[fld.Name for relation]")
        rel.Fields("[fld.Name for relation]").ForeignName = "[fld.Name for relation]"
        .Relations.Append rel
    End With
End Function

Error handling and IO omitted due to time constraints (gotta put the kids to bed).

Hope this helps.

Patrick Cuff
Wonderful, thanks.
lamcro
A: 

It occurs to me that you can use a backup of the file made before any changes to restore the indexes and relations. Here are some notes.

Sub RunExamples()
Dim strCopyMDB As String
Dim fs As FileSystemObject
Dim blnFound As Boolean
Dim i

' This code is not intended for general users, it is sample code built '
' around the OP '
'You will need a reference to the Microsoft DAO 3.x Object Library '
'This line causes an error, but it will run '
'It is not suitable for anything other than saving a little time '
'when setting up a new database '
Application.References.AddFromFile ("C:\Program Files\Common Files\Microsoft Shared\DAO\dao360.dll")

'You must first create a back-up copy '
Set fs = CreateObject("Scripting.FileSystemObject")

strCopyMDB = CurrentProject.Path & "\c.mdb"
blnFound = fs.FileExists(strCopyMDB)

i = 0
Do While blnFound
    strCopyMDB = CurrentProject.Path & "\c" & i & ".mdb"
    blnFound = fs.FileExists(strCopyMDB)
Loop

fs.CopyFile CurrentProject.FullName, strCopyMDB

ChangeTables
AddIndexesFromBU strCopyMDB
AddRelationsFromBU strCopyMDB
End Sub  


Sub ChangeTables()
Dim db As Database
Dim tdf As DAO.TableDef
Dim rel As DAO.Relation
Dim fld As DAO.Field
Dim ndx As DAO.Index
Dim i

    Set db = CurrentDb
    'In order to programmatically change an autonumber, '
    'it is necessary to delete any relationships that '
    'depend on it. '  
    'When deleting from a collection, it is best '
    'to iterate backwards. '
    For i = db.Relations.Count - 1 To 0 Step -1
        db.Relations.Delete db.Relations(i).Name
    Next

    'The indexes must also be deleted or the '
    'number cannot be changed. '
    For Each tdf In db.TableDefs
        If Left(tdf.Name, 4) <> "Msys" Then
            For i = tdf.Indexes.Count - 1 To 0 Step -1
                tdf.Indexes.Delete tdf.Indexes(i).Name
            Next

            tdf.Indexes.Refresh

            For Each fld In tdf.Fields
                'If the field is an autonumber, '
                'use code supplied by MS to change the type '
                If (fld.Attributes And dbAutoIncrField) Then

                    AlterFieldType tdf.Name, fld.Name, "Long"

                End If
            Next
        End If

    Next
End Sub


Sub AddIndexesFromBU(MDBBU)
Dim db As Database
Dim dbBU As Database
Dim tdf As DAO.TableDef
Dim tdfBU As DAO.TableDef
Dim ndx As DAO.Index
Dim ndxBU As DAO.Index
Dim i

Set db = CurrentDb
'This is the back-up made before starting '
Set dbBU = OpenDatabase(MDBBU)

    For Each tdfBU In dbBU.TableDefs
        'Skip system tables '
        If Left(tdfBU.Name, 4) <> "Msys" Then
            For i = tdfBU.Indexes.Count - 1 To 0 Step -1
                'Get each index from the back-up '
                Set ndxBU = tdfBU.Indexes(i)
                Set tdf = db.TableDefs(tdfBU.Name)
                Set ndx = tdf.CreateIndex(ndxBU.Name)
                ndx.Fields = ndxBU.Fields
                ndx.IgnoreNulls = ndxBU.IgnoreNulls
                ndx.Primary = ndxBU.Primary
                ndx.Required = ndxBU.Required
                ndx.Unique = ndxBU.Unique

                ' and add it to the current db '
                tdf.Indexes.Append ndx
            Next

            tdf.Indexes.Refresh
        End If
    Next

End Sub

Sub AddRelationsFromBU(MDBBU)
Dim db As Database
Dim dbBU As Database
Dim rel As DAO.Relation
Dim fld As DAO.Field
Dim relBU As DAO.Relation
Dim i, j, f

On Error GoTo ErrTrap

    Set db = CurrentDb
    'The back-up again '
    Set dbBU = OpenDatabase(MDBBU)

    For i = dbBU.Relations.Count - 1 To 0 Step -1
        'Get each relationship from bu '
        Set relBU = dbBU.Relations(i)
        Debug.Print relBU.Name
        Set rel = db.CreateRelation(relBU.Name, relBU.Table, relBU.ForeignTable, relBU.Attributes)
        For j = 0 To relBU.Fields.Count - 1
            f = relBU.Fields(j).Name
            rel.Fields.Append rel.CreateField(f)
            rel.Fields(f).ForeignName = relBU.Fields(j).ForeignName
        Next
        'For some relationships, I am getting error'
        '3284 Index already exists, which I will try'
        'and track down tomorrow, I hope'
        'EDIT: Apparently this is due to Access creating hidden indexes
        'and tracking these down would take quite a bit of effort
        'more information can be found in this link:
        'http://groups.google.ie/group/microsoft.public.access/browse_thread/thread/ca58ce291bdc62df?hl=en&amp;ie=UTF-8&amp;q=create+relation+3284+Index+already+exists
        'It is an occasional problem, so I've added an error trap

         'Add the relationship to the current db'
         db.Relations.Append rel
    Next
ExitHere:
    Exit Sub

ErrTrap:
    If Err.Number = 3284 Then
        Debug.Print relBU.Name, relBU.Table, relBU.ForeignTable, relBU.Attributes
        Resume Next
    Else
        'this is not a user sub, so may as well ... '
        Stop

End If
End Sub

Sub AlterFieldType(TblName As String, FieldName As String, _
    NewDataType As String)
'http://support.microsoft.com/kb/128016'

    Dim db As Database
    Dim qdf As QueryDef
    Set db = CurrentDb()

    ' Create a dummy QueryDef object.'
    Set qdf = db.CreateQueryDef("", "Select * from PROD1")

    ' Add a temporary field to the table.'
    qdf.SQL = "ALTER TABLE [" & TblName & "] ADD COLUMN AlterTempField " & NewDataType
    qdf.Execute

    ' Copy the data from old field into the new field.'
    qdf.SQL = "UPDATE DISTINCTROW [" & TblName _
        & "] SET AlterTempField = [" & FieldName & "]"
    qdf.Execute

    ' Delete the old field.'
    qdf.SQL = "ALTER TABLE [" & TblName & "] DROP COLUMN [" _
       & FieldName & "]"
    qdf.Execute

    ' Rename the temporary field to the old field's name.'
    db.TableDefs("[" & TblName & "]").Fields("AlterTempField").Name = FieldName

End Sub
Remou
It looks like the first thing this code does is to delete all of the relationships. Once you've done that you won't be able to export them.
Eric Ness
I think you may have missed the first text line which says 'You must first create a back-up copy called C.mdb in this example'
Remou
Even so, do you really think a solution that depends on the user remembering to back up is really the best solution?
Kyralessa
It is not a user solution. The original post depends on manually changing each table autonumber to an integer. The notes (I did say notes) shows how the OP, who is the developer, could save a little time by programmatically changing the tables.
Remou
I also think it is reasonably safe to assume that the developer would create a back up before making such drastic changes to the tables.
Remou
Why shouldn't the code do the backup?
David-W-Fenton
It does at this stage. But it never occurred to me that it would be necessary to expand a suggestion for getting indexes back into every corner of the suggestion. It is, after all, a forum for programmers and backing up a file is not difficult coding and probably unnecessary for once-off code..
Remou
oops replace indexes with relationships in the previous comment. I might mention that this code does get your relationships back, not just print them out, except for a possible fail where an index is automatically created by Access. There is even a hint for overcoming this problem.
Remou
A: 

Please refer the below article http://www.codeproject.com/KB/office/VBAMacro.aspx

A: 

Thanks for code snippet.. to get rid of your 3284 error I have chnaged few things... If you copy all indexes from sample mdb and then try to put relaships it throws an exception as it expects no idexes for relationshisps. when u put relationships it put its own indexes... Steps I followed are.. assume target.mdb and source.mdb 1. Run this code in target.mdb remove all indexes and relationsships frmo target.mdb by calling ChangeTables 2. call AddIndexesFromBU source.mdb and use condition
If ndxBU.Unique Then tdf.Indexes.Append ndx End If this willput just Unique index 3. call AddRelationsFromBU source.mdb and put all relationsships 4.Call again AddIndexesFromBU source.mdb and change condition to If not ndxBU.Unique Then
I have also added error trap same as AddRelationsFromBU in AddIndexesFromBU and resume next for if ans else

This worked for me Vivek

Vivek