插入到MySQL后端中的两个表构建的MS Access查询中,并具有一对一的关系?

时间:2014-05-14 12:28:46

标签: mysql ms-access sql odbc

我们有一个通过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;
如果只输入父表(即Model)的数据,

Access将允许您向查询添加行。这当然只在Parent表中创建一行。当您尝试在ModelNum字段中键入任何内容时,Access会阻止它并在状态栏中显示上述错误消息。

我尝试在“访问关系”窗口中创建关系。我已将TIMESTAMP列添加到两个表中。我还使用wireshark来嗅探MySQL连接;当显示错误时,访问似乎不会发送任何内容。

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

我们正在使用MS Access 2007和MariaDB 5.5.37。谢谢!

1 个答案:

答案 0 :(得分:0)

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

在Access数据库中创建一个Pass Through查询,其连接字符串具有执行插入的正确凭据。我不是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 db的代码。在生产中,当然需要注意动态SQL的所有常规问题。此外,使用QueryDefs的SQL属性,它在您分配时更改并保存,因此您需要以某种方式保留原始SQL(您可以在代码,连接字符串和代码中创建整个QueryDef,甚至)。你可以找到最适合自己的方法。

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

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

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