现在我们计划通过Passthrough查询替换所有本地查询,以便直接使用本机sql Server表.
我尝试使用以下sql字符串创建一个名为qrySelProductsPassThroughEditable的非常简单的passthru查询:
SELECT dbo.Products.ID,dbo.Products.Name FROM dbo.Products;
ID字段是在sql Server中定义为主键的IDENTITY字段作为定义:
CREATE TABLE [dbo].[Products]( [ID] [int] IDENTITY(1,1) NOT NULL,.... )
但Access传递查询返回的数据表根本不可编辑.所以它不能用作.RecordSource来编辑表单.
这与the link相反,后者表示如果passthru查询包含所有相关表的所有主键,则查询将是可编辑的.
结论添加了一个后验
通过下面的讨论,Microsoft Access 2007 .accdb,.accde或.accdr(Access运行时)中的直通查询始终是只读的,它永远不可编辑.您应该将它用作最终列表,或者作为报表的.RecordSource,而不是用于必须使用链接表的表单,或者是涉及数据IO的链接表的可写普通查询.
解决方法
基本上有两种方法可以将Access连接到非Access数据源.
第一种方法,也是最流行的方法,是使用某种形式的链表,通常是ODBC链表.有多种方法可以将ODBC链接表与MS Access一起使用,但大多数开发人员更喜欢使用在应用程序启动时刷新或重建(删除并重新连接)的DSN-Less连接.请注意,使用ODBC时,您仍然使用DAO. DAO是MS Access中内置的默认数据访问对象,即使您没有专门编写任何DAO代码,MS Access仍然使用DAO将表单,报表和查询链接到您的数据源.在ODBC的情况下,实际上最终有两个数据访问层在工作,DAO和ODBC.但是你可以使用相当不错的ODBC / DAO并且无需编写代码(除了维护ODBC链接表之外).
第二种方法是使用ADO.与流行的看法相反,这并不意味着您必须使用未绑定的表格.但它确实意味着您必须编写比使用JET / DAO / MSAccess或DAO / ODBC / Ssql Server更多的代码.您必须编写代码以将数据库中的记录引入ADO Recordset,然后使用代码将表单绑定到该Recordset.您必须编写更多代码以使子表单与父表单保持同步,在创建新记录时将外键插入子表单,并且可能还包括过滤和排序等各种其他内容. ADO是一种与sql Server交流的好方法,因为它真的给你很多控制权,但由于代码密集,并且因为ODBC链接表工作得很好,大多数开发人员不推荐使用ADO,除非没有别的方法可以做什么你想做什么.这方面的一个例子是调用存储过程.我相信Pass Through Queries可用于调用存储过程,但我也认为存在一些限制(例如使用参数).我相信在大多数情况下,开发人员使用ADO来调用存储过程.我经常使用ADO,但是我没有使用存储过程(还没有),所以我没有太多关于它的信息.
我自己创建单个DSN-Less ODBC Linked表的功能如下所示.如果您是Access和VBA的新用户,这可能对您没有多大意义.代码删除了您尝试链接的表已存在的任何表定义,这有点危险,因为我相信它可以删除您不想要的本地非链接表.这里的错误处理也没有真正达到速度,但是由于涉及的复杂性,大多数在线示例代码在其中没有良好的错误处理.在链接表上创建主键索引并不总是必要的.我只是将它内置到我的函数中,因为我需要一次特定项目,所以现在我把它留在那里并使用它,无论好坏.
要正确使用此代码,您确实需要在某处列出所有链接表,并遍历该列表并为每个表调用此函数.此功能允许您使用与sql Server中的实际名称不同的名称链接表.您还需要一种构建有效ODBC连接字符串的方法,该字符串也必须传递给此函数.
Private Sub LinkODBCTable(sSourceTableName As String,_ sLocalTableName As String,_ sPrimaryKeyField As String,_ sConString As String) Dim dbCurrent As DAO.Database Dim tdfCurrent As DAO.TableDef Set dbCurrent = DBEngine.Workspaces(0).Databases(0) On Error Resume Next 'Be Careful,this could delete a local,non-linked table. dbCurrent.TableDefs.Delete sLocalTableName If Err.Number <> 0 Then If Err.Number = 3011 Then 'Table does not exist Else MsgBox "Error in LinkODBCTable" & vbCrLf & vbCrLf & Err.Number & " " & Err.Description End If Err.Clear End If On Error GoTo 0 Set tdfCurrent = dbCurrent.CreateTableDef(sLocalTableName) tdfCurrent.Connect = sConString tdfCurrent.sourceTableName = sSourceTableName dbCurrent.TableDefs.Append tdfCurrent On Error Resume Next If sPrimaryKeyField <> "" Then dbCurrent.Execute "CREATE INDEX __UniqueIndex ON [" & sLocalTableName & "] (" & sPrimaryKeyField & ")",dbFailOnError If Err.Number <> 0 Then If Err.Number = 3283 Then 'Primary Key Already Exists Else MsgBox "Error in LinkODBCTable" & vbCrLf & vbCrLf & Err.Number & " " & Err.Description End If Err.Clear End If End If Set tdfCurrent = Nothing Set dbCurrent = Nothing End Sub
有关DAO,ADO,Pass Through Queries,sql Server等应该检查的一些非常好的资源:
http://technet.microsoft.com/en-us/library/bb188204%28v=sql.90%29.aspx
http://www.utteraccess.com/wiki/index.php/Choosing_between_DAO_and_ADO
这是将表单绑定到ADO Recordset的示例.这有点误导,因为最好让一个全局连接对象在应用程序运行时保持打开状态.这允许您使用可自动更新的ADO记录集.使用此练习还可能使您的记录集成为表单级对象.
http://msdn.microsoft.com/en-us/library/office/bb243828%28v=office.12%29.aspx