我们有一个通过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。谢谢!
答案 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。您可以使用自己认为合适的代码来操纵代码。再一次,只是一个概念证明,你可以通过多种方式实现;也许您的传递查询会执行存储过程并传递参数。无论如何,我认为这为您的需求提供了一个不错的解决方案,并且应该与您的整个应用程序相关。希望有所帮助。