【问题标题】:MS ACCESS 2003 triggers (Query Event), and Excel importMS ACCESS 2003 触发器(查询事件)和 Excel 导入
【发布时间】:2013-06-18 15:24:05
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

    标签: sql excel ms-access


    【解决方案1】:

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

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

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

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

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

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

    表 2:地址(ID、街道)

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

    客户: ID、姓名、地址ID 1,鲍勃,1 2,吉姆,2

    地址: 身份证,街道 1、黄金街 2、德普街

    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 文本 (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
    

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

    【讨论】:

    • 感谢您的宝贵时间和帮助。我不得不承认我对 VBA 并不了解,但你的解释很有帮助。我会做功课并阅读您发布的链接(如果需要,还可以阅读更多链接)。 VBA还能帮我解决列依赖其他列的问题吗(比如price_with_taxes = price_w/o_taxes*1.2)??
    • 您可以根据数据表创建查询,其中新字段按照您的描述定义。因此,在 datatable1 中,您将 price 作为数据列,然后在 query1(基于 table1)中包含 table1 中的所有字段,此外还有一个名为 price_with_taxes 的字段:(价格 * 1.2)。这符合您的要求吗?
    • 非常好,谢谢大家的帮助。从昨天开始,我一直在阅读有关 VBA 的信息,如果您使用的是 Microsoft 产品,我可以看到它是一个很好的解决方案。在使用和修改代码之前,我喜欢阅读它。根据我的阅读,我所有的问题都可以用 VBA 解决。如果在编码过程中,我再次挣扎,那么我会指望你们;)。放心,我不会用问题侵占你的空间和时间XD。
    【解决方案2】:

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

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

    【讨论】:

    • 感谢您的宝贵时间和建议。我已经使用了access提供的关系工具,对于直接链接的表来说效果很好。但是如果两个表通过 1 个或多个表链接,则不能确保引用完整性,除非我创建一个循环。 (表 1 -> 表 2 -> 表 3 和表 1 -> 表 3)。但是我知道这样做不是一个好习惯。
    • 引用完整性中的示例听起来不正确。如果表 3 中的链接引用了表 2 中限制为表 1 中的值的列,则完整性限制将遍历所有三个表。稍后您可能在更新值时遇到问题,但是,键不应该是可变的!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    相关资源
    最近更新 更多