0

我正在一家公司从事一个项目,因此我必须使用在 XP 上运行的 MS ACCESS 2003(尽管我认为操作系统在这里不相关)。由于公司正在使用其他应用程序(以及外部资源),因此用作表中输入的数据并不总是经过清理。但是,我注意到我们总是可以获取 .XLS (excel) 格式的数据。

数据库由40多张表组成,有冗余、无键、无索引;换句话说,这是一团糟。经过很多麻烦,我能够改进设计并减少表的数量。

然而,我发现自己面临的挑战很少。大多数这些挑战都可以通过触发器来克服,但是在阅读了不同论坛中的许多答案后,我了解到它们在 access 2003 中不存在,应该用与表单相关的查询替换。这种解决方案的一个问题是它需要一个表单和一个按钮。所以我想,在使用表单从 excel 文件中导入数据时,我会实现这样的查询。由于表格不完全遵循 excel 文件的格式,我需要指导学习如何从特定工作表中导入特定的 excel 列,将目录更改为 Db 中表格的相应列。

此外,这也是它变得更具挑战性的地方(至少对我而言),我有不同的表没有直接连接(例如桥表),但我仍然需要在所有表的数据之间保持一定的完整性。如果我们有表 A、B、C;表 A 连接到连接到表 C 的表 B:我需要在表 A 中插入行时插入或删除表 C 的行。此外,我需要表 C 的某些列保持一致(就值)与表 A 的列。我知道这起初看起来像是设计中的一个问题,但我向你保证它不是。很抱歉没有提供表格的详细信息,但我签署了保密条款。

最后,这似乎是一个“愚蠢”的问题,但我无法在访问表设计中找到根据其他列对某些列强加一些数学验证规则的地方。我发现我们可以在单个列上设置验证规则(例如 Is Null Or >= 0),但对于某些列,它们的值应该取决于其他列。例如,B 列应该等于 1.2*A 列(有时这些列在同一个表中,但并非总是如此)。

谢谢您的帮助。我非常感谢您在我面临的任何问题上提供的任何帮助;对于您可能需要的任何其他信息,我随时待命。

4

2 回答 2

2

我同意user2174085,你的问题有很多。

我的方法是在类中对您的数据进行建模,并使用它们写入您的数据库。这将允许您根据需要验证数据,并将数据导入到所需数量的表中。

这种方法在 CRUD 应用程序中是标准的。

这是一个用于说明目的的简单示例,其中(我希望)清楚地描述了步骤):

1)定义我们的示例数据库:

表 1:客户端(ID、名称、地址 ID)

表 2:地址(ID、街道)

2) 定义我们的示例电子表格:

客户:ID、姓名、地址ID 1、Bob、1 2、Jim、2

地址:ID, Street 1, Gold Street 2, Derp Street

3) 定义我们的 2 个类,它们允许我们对单个客户端和单个地址进行建模。

要在 MS Access 中使用这些,请在代码编辑器窗口中添加一个类并粘贴以下类。有关更多信息,这是一个很好的 vba 类资源:http ://www.cpearson.com/excel/classes.aspx

客户端类:

Option Compare Database
Option Explicit

Dim intID As Integer
Dim strName As String
Dim intAddressID As Integer

'here we define a query (QueryDef) which is in the database (usp_Clients_InsertRecord), populate its parameters from the class variables and execute it to write the record
Public Sub Insert()
    Dim qdfTemp As QueryDef
    Set qdfTemp = CurrentDb().QueryDefs("usp_Clients_InsertRecord")
    With qdfTemp
        .Parameters("pName") = strName
        .Parameters("pAddressID") = pAddressID
    End With
    qdfTemp.Execute
End Sub

地址类:

Option Compare Database
Option Explicit

Dim intID As Integer
Dim strStreet As String

'here we define a query (QueryDef) which is in the database (usp_Addresses_InsertRecord),     populate its parameters from the class variables and execute it to write the record
Public Sub Insert()
    Dim qdfTemp As QueryDef
    Set qdfTemp = CurrentDb().QueryDefs("usp_Addresses_InsertRecord")
    With qdfTemp
        .Parameters("pStreet") = strStreet
    End With
    qdfTemp.Execute
End Sub

此时您可以执行验证,例如,您可以创建一个客户端记录,然后调用一个验证方法来告诉您数据是否正常。

未写入 ID 的原因是因为它是数据库中的自动编号。它仍然包含在类中,因为我们可能需要从数据库中的数据创建客户/地址记录,并使用其信息写入另一条记录。例如,要写入客户记录,我们可能需要检索地址记录,并带有用于写入客户记录的 AddressID。

4)以上类使用查询(存储过程)写入数据库,这里是一个示例查询:

usp_Clients_InsertRecord

参数 pName Text (255), pAddressID Long; 插入客户(姓名,地址ID)值(pName,pAddressID);

5)这一切都很好,但是我们如何从excel中获取数据,进入类,将其写入数据库?为此,我们使用管理类,这些类包含大量客户端或地址记录,从电子表格加载并存储在集合中。循环这个集合,调用 Insert 方法将记录写入数据库。

这为您的问题提供了一个答案,即如何将数据写入表 A,然后是 B,然后是 C。您将创建 3 个类,用数据填充它们,然后将 A 写入数据库,然后使用最后写入记录的 ID 写入 B到表 A(使用查询检索)等等。

下面是一个管理类的例子:

Option Explicit
'our clients collection
Private mcolClients As Collection
'adding objects to the clients collection
Public Function AddByParameter(byval Name as string, byval AddressID as integer)
    dim objClient as Client
    Set objClient = New Client
    with objClient
        .strName = Name
        .intAddressID = AddressID
    end with
    mcolClients.Add objClient, Name
end function
'constructor
Private Sub Class_Initialize()
    Set mcolClients = New Collection
End Sub
'you need this to be able to iterate over a collection
Public Function NewEnum() As IUnknown
  Set NewEnum = mcolImportQuestions.[_NewEnum]
End Function
'you can then iterate over the collection, calling the insert method on each record:
public Sub InsertAllClients
    dim objClient as Client
    for each objClient in mcolClients
        objClient.Insert
    next objClient
end function

我想我已经走了一点,如果这有用,请告诉我/提出问题,我可以充实一下:)

于 2013-06-18T17:52:21.843 回答
1

老实说,您可能想分别提出这些问题。我们都有日常工作,只能花一点时间来提供帮助!:o)

我可以快速回答的一个问题是关于数据完整性的问题。如果单击工具,然后单击关系,则可以设置表之间的关系。正是在这些关系中,您可以“实施参照完整性”。这是 Access 将自动删除相关表中的记录以保持数据清洁的地方。

于 2013-06-18T16:36:22.633 回答