将嵌套表导出到新的后端

时间:2016-08-05 11:26:22

标签: vba ms-access sql-insert

我有一个Access后端数据库,其中包含7个嵌套的相关表:客户端,项目,项目目标,目标障碍,障碍原因,可能的解决方案和所需的操作或资源。每个客户可能有多个项目。每个项目可能在目标行动中有多个记录。

我想将一个带有嵌套表的客户端项目导出到具有完全相同结构的空后端,因此提供前端和后端的客户端可以查看信息并进行更改。如果客户端进行了更改,我想将更改导回到master数据库,替换现有数据。

客户拥有通常的个人信息。项目有八个字段,包括客户端的链接ID。从目标到操作的每个表都有一个自动编号的主键,一个链接到上表主键的ID字段,一个100字符的简短描述,一个用于Notes的长字段,一个用于优先级或加权重要性的数字以及一个是/否字段已解决或已完成。每个可能有1到10条记录。我正在使用的样本记录集中有94条记录。

使用查询从数据库中提取项目及其相关数据非常容易;但我无法想出最有效的方法将其插入空的后端。我在Export按钮下启动了一些子程序来按表传输数据表,因此我可以处理由重新编号的主键引起的更改关系;但如果可能的话,我想一举做好整个过程。我创建了一个巨大的后端文件,其中有一个有缺陷的尝试,而不是rsSource.EOF - Wend例程。感激地收到任何建议。

********************************代码************** ********************

Private Sub Command316_Click()
' SelectedClient and SelectedProject are Public Integer variables
' To be used in For...Next loops
Dim i, iNumRecs, intGoal, intImped, intCause, intSolution, intAction As Integer
Dim SQLstr As String

'Open source database
Dim dbSource As Database
Set dbSource = CurrentDb

'Open dest database
Dim dbDestination As Database
Set dbDestination = DAO.OpenDatabase("C:\Prosolve\Temp\Prosolve_BE.accdb")

' Select Project to be transferred
' Might be easier to work with if everything NOT selected at once

SQLstr = "SELECT Clients.ClientID, Clients.ContactFirstName, Clients.ContactLastName, Clients.Address, Clients.City, Clients.StateOrProvince, Clients.PostalCode, "
SQLstr = SQLstr + "Clients.Country, Clients.EmailAddress, Clients.CompanyName, Clients.PhoneNumber, Clients.CellNumber, Clients.BillingRate, Clients.TaxPayable, Clients.Discount, "
SQLstr = SQLstr + "Projects.ProjectID, Projects.ClientID, Projects.ProjectName, Projects.ProjectOwner, Projects.ProjectDescription, Projects.EmployeeID, Projects.Priority, Projects.TotalBilled, "
SQLstr = SQLstr + "Goals.GoalID, Goals.ProjectID, Goals.Goal, Goals.Notes, Goals.Owners, Goals.Gpriority, "
SQLstr = SQLstr + "Impediments.ImpedID, Impediments.IgoalID, Impediments.Impediment, Impediments.Notes, Impediments.Iweight, Impediments.Resolved, "
SQLstr = SQLstr + "Causes.CauseID, Causes.cimpedID, Causes.cause, Causes.Notes, Causes.cweight, Causes.resolved, "
SQLstr = SQLstr + "Solutions.SolutionID, Solutions.ScauseID, Solutions.Solution, Solutions.Notes, Solutions.Sweight, Solutions.Implemented, "
SQLstr = SQLstr + "Actions.ActionID, Actions.AsolutionID, Actions.Action, Actions.Notes, Actions.Priority, Actions.Completed "
SQLstr = SQLstr + "FROM ((Clients INNER JOIN Projects ON Clients.ClientID = Projects.ClientID) "
SQLstr = SQLstr + "INNER JOIN ((Goals INNER JOIN Impediments ON Goals.GoalID = Impediments.IgoalID) "
SQLstr = SQLstr + "INNER JOIN (Causes INNER JOIN Solutions ON Causes.causeID = Solutions.ScauseID) "
SQLstr = SQLstr + "ON Impediments.ImpedID = Causes.cimpedID) ON Projects.ProjectID = Goals.ProjectID) "
SQLstr = SQLstr + "INNER JOIN Actions ON Solutions.SolutionID = Actions.AsolutionID "
SQLstr = SQLstr + "WHERE Clients.ClientID = " & SelectedClient & " AND Projects.ProjectID = " & SelectedProject & " ;"


'Open source recordset
Dim rsSource As Recordset
Set rsSource = dbSource.OpenRecordset(SQLstr, dbOpenDynaset)

'Open dest recordset
Dim rsDestination As Recordset
Set rsDestination = dbDestination.OpenRecordset("Clients", dbOpenDynaset)

'Loop through source recordset
'While Not rsSource.EOF

    'Look for record in dest recordset
    rsDestination.FindFirst "ContactFirstName = '" & rsSource.Fields("ContactFirstName") & "'"
    '& " AND ContactLastName = " & rsSource.Fields("ContactLastName") & ""

    'If not found, copy record
    'Works okay
    If rsDestination.NoMatch Then
        rsDestination.AddNew
        rsDestination.Fields("ContactFirstName") = rsSource.Fields("ContactFirstName")
        rsDestination.Fields("ContactLastName") = rsSource.Fields("ContactLastName")
        rsDestination.Fields("Address") = rsSource.Fields("Address")
        rsDestination.Fields("City") = rsSource.Fields("City")
        rsDestination.Fields("StateOrProvince") = rsSource.Fields("StateOrProvince")
        rsDestination.Fields("PostalCode") = rsSource.Fields("PostalCode")
        rsDestination.Fields("Country") = rsSource.Fields("Country")
        rsDestination.Fields("EmailAddress") = rsSource.Fields("EmailAddress")
        rsDestination.Fields("CompanyName") = rsSource.Fields("CompanyName")
        rsDestination.Fields("PhoneNumber") = rsSource.Fields("PhoneNumber")
        rsDestination.Fields("CellNumber") = rsSource.Fields("CellNumber")
        rsDestination.Fields("BillingRate") = rsSource.Fields("BillingRate")
        rsDestination.Fields("TaxPayable") = rsSource.Fields("TaxPayable")
        rsDestination.Fields("Discount") = rsSource.Fields("Discount")
        rsDestination.Update
    Else
    MsgBox "Record alreasy exists"
    End If
'Works okay
Set rsDestination = dbDestination.OpenRecordset("Projects", dbOpenDynaset)
    rsDestination.FindFirst "ClientID = 1"
    If rsDestination.NoMatch Then
        rsDestination.AddNew
        rsDestination.Fields("ClientID") = 1
        rsDestination.Fields("ProjectName") = rsSource.Fields("ProjectName")
        rsDestination.Fields("ProjectOwner") = rsSource.Fields("ProjectOwner")
        rsDestination.Fields("ProjectDescription") = rsSource.Fields("ProjectDescription")
        rsDestination.Fields("EmployeeID") = rsSource.Fields("EmployeeID")
        rsDestination.Fields("Priority") = rsSource.Fields("Projects.Priority")
        rsDestination.Fields("TotalBilled") = rsSource.Fields("TotalBilled")
        rsDestination.Update
    Else
    MsgBox "Record alreasy exists"
    End If

' Try to find number of Goals for a For ... Next procedure
' Not counting Goals in Query. Will cause problems later when 2 or more client have same ProjectID
iNumRecs = DCount("ProjectID", "Goals", "ProjectID = " & SelectedProject & "")

'Here we need to copy all goals for projectID = 1 from 1 to number of goals'
' Once this is done successfully the process can be repeated for tables below it
'Loop through source recordset
'Currently copies 6 x first goal. rsSource.Movenext not working.
Set rsDestination = dbDestination.OpenRecordset("Goals", dbOpenDynaset)
    rsDestination.FindFirst "ProjectID = " & SelectedProject & ""
    If rsDestination.NoMatch Then
    For i = 1 To iNumRecs
        rsDestination.AddNew
        rsDestination.Fields("ProjectID") = SelectedProject
        rsDestination.Fields("Goal") = rsSource.Fields("Goal")
        rsDestination.Fields("Notes") = rsSource.Fields("Goals.Notes")
        rsDestination.Fields("Owners") = rsSource.Fields("Owners")
        rsDestination.Fields("Gpriority") = rsSource.Fields("Gpriority")
        rsDestination.Update
        rsSource.MoveNext
    Next
    Else
    MsgBox "Record alreasy exists"
    End If


MsgBox "Procedure successfully completed to this point"

End Sub

********************************结束代码************* *********************

1 个答案:

答案 0 :(得分:0)

您正在构建一个包含所有表连接的巨型源记录集。因此,此记录集将包含大量记录(在您的示例中为94),但您导出的各种表记录较少。

当你知道你只需要将一条记录插入目标记录集(客户端,项目)时,这就有效,但如果记录的数量可变,它就不会有效。

使用目标,您可以使用DCountFor循环限制其数量,但您只需获取巨型来源的前6条记录。由于连接,这通常是目标的6倍。

您应该为所有表创建单独的源记录集,每个表在客户端/项目上都有一个WHERE子句。然后,您可以将所有记录从源复制到目标。

更容易的方法是:

将所有表的INSERT语句直接运行到目标数据库中。

INSERT INTO [Goals] IN 'C:\Prosolve\Temp\Prosolve_BE.accdb'
SELECT *
FROM Goals
WHERE Goals.ProjectID = 1;

请注意,这也适用于AutoNumber列。

请注意,困难的部分仍然领先于您:导入更改的数据不会那么容易。有多难取决于客户端是否只能更改现有数据,还是可以添加/删除记录。