【问题标题】:Insert into a MS Access query built from two tables in a MySQL backend with a one-to-one relationship?插入从具有一对一关系的 MySQL 后端中的两个表构建的 MS Access 查询中?
【发布时间】:2014-05-14 12:28:46
【问题描述】:

我们有一个通过 ODBC 连接到 MySQL 后端的 MS Access 前端。我们正在尝试将两个具有一对一关系的表移动到后端。然后,我们有一个 Access 查询,将表与 INNER JOIN 组合起来,并将查询显示为表单上的数据表。

当表在 Access 中(未链接)时,您可以在查询数据表视图中添加一行,然后 Access 在两个表中创建具有相同主键的行。当表被移动到 MySQL 后端时,尝试在查询中插入新记录被阻止,状态栏中出现错误:

Cannot add record(s); primary key for table `Child` not in recordset.

以下是简化的表和查询定义:

-- MySQL table definitions:
CREATE TABLE Parent (
  ID int(11) NOT NULL AUTO_INCREMENT,
  Model varchar(255) DEFAULT NULL,
  PRIMARY KEY (ID)
);

CREATE TABLE Child (
  ID int(11) NOT NULL DEFAULT '0',
  ModelNum int(11) DEFAULT NULL,
  PRIMARY KEY (ID),
  CONSTRAINT fk_Child_Parent FOREIGN KEY (ID) REFERENCES Parent (ID)
);

-- MS Access Query:
SELECT Parent.ID, Parent.Model, Child.ModleNum
FROM Parent INNER JOIN Child ON Parent.ID = Child.ID;

如果您只为父表(即模型)输入数据,Access 将允许您在查询中添加一行。这当然只会在 Parent 表中创建一行。当您尝试在 ModelNum 字段中键入任何内容时,Access 会阻止它并在状态栏中显示上述错误消息。

我尝试在“访问关系”窗口中创建关系。我在两个表中都添加了 TIMESTAMP 列。我还使用wireshark 来嗅探MySQL 连接; Access 在显示错误时似乎没有发送任何内容。

是否可以让 Access 做正确的事情?它应该发送一个INSERT INTO Parent,获取ID,然后使用该密钥获取INSERT INTO Child。我可以添加一个按钮并在 VBA 中执行此操作,但在我们的实际应用程序中,有许多相关的表格和必须复制功能的地方。我们可以使用触发器来创建子行,但这并不适用于实际应用程序中的所有情况。

我们使用的是 MS Access 2007 和 MariaDB 5.5.37。谢谢!

【问题讨论】:

    标签: mysql ms-access sql odbc


    【解决方案1】:

    知道你问这个问题已经有一段时间了,但我想我会给我两分钱。我认为您在这里要做的是设置一个通过查询来完成繁重的工作,将两个 INSERT 包装在事务中,然后通过 VBA 执行代码。这是概念的快速证明。

    在您的 Access 数据库中创建一个直通查询,其连接字符串具有执行插入的正确凭据。我不是 MYSQL 人,但根据我的研究,下面的 SQL 应该没问题:

    BEGIN;
    
    DECLARE @ID INT;
    
    INSERT Parent(Model)
    VALUES('~Parent_Model');
    
    SET @ID = LAST_INSERT_ID();
    
    INSERT Child(ID, ModelNum)
    VALUES(@ID, ~Child_ModelNum);
    
    COMMIT;
    

    您应该在您的本地 MYSQL 环境中运行此代码(将 ~Parent_Model 和 ~Child_ModelNum 替换为一些用于测试的值)以确保该代码段正常工作。它所做的是向 Parent 添加一条记录,获取最后一个自动添加的 ID 号(用于会话)并将其存储在 @ID 中,然后使用该值插入到 Child 表中。将此查询另存为 qryInsert。

    下面是一些执行查询的代码:

    Public Sub InsertTest(Parent_Model As String, Child_ModelNum As Integer)
    On Error GoTo ErrorHandler
    
        Dim db As DAO.Database
        Dim qdf As DAO.QueryDef
        Dim strOriginalSQL As String
    
        Set db = CurrentDb()
        Set qdf = db.QueryDefs("qryInsert")
    
        strOriginalSQL = qdf.SQL
    
        qdf.SQL = Replace(qdf.SQL, "~Parent_Model", Parent_Model)
        qdf.SQL = Replace(qdf.SQL, "~Child_ModelNum", Child_ModelNum)
    
        qdf.ReturnsRecords = False
        qdf.Execute
    
    ExitMe:
        qdf.SQL = strOriginalSQL
        Set qdf = Nothing
        Set db = Nothing
    
        Exit Sub
    ErrorHandler:
        Debug.Print Err.Number & ": " & Err.Description
        GoTo ExitMe
    
    End Sub
    

    代码正在访问您之前所做的查询,将 ~Parent_Model 和 ~Child_ModelNum 替换为传入的参数(传递查询的参数有点不稳定,所以我只是这样做以显示概念),然后执行针对 MYSQL 数据库的代码。当然,在生产环境中,您必须注意动态 SQL 的所有常见问题。此外,使用 QueryDefs 的 SQL 属性,它会在您分配时更改并保存,因此您需要以某种方式保留原始 SQL(您可以在代码、连接字符串和所有代码中创建整个 QueryDef,甚至)。您可以为自己找出最好的方法。

    为了运行代码,我添加了一个带有一些测试值的快速包装器:

    Public Sub RunInsertTest()
        Call InsertTest("From Access", 1232)
    End Sub
    

    如果您单步执行代码并一直遵循它,您应该将记录添加到两个表中,并具有相同的 ID。您可以利用您认为适合您的应用程序的代码。同样,这只是一个概念证明,您可以通过多种方式实现;也许您通过查询执行存储过程并传递参数。无论如何,我认为这为您的需求提供了一个不错的解决方案,并且应该与您的整个应用程序相关。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多