7

在带有 SQL Server Backend 的 Microsoft Access 2007 中,我们通常会从 SQL Server 中获取一个链接表作为可编辑表单的 Form.RecordSource,用于单表数据修改。本地查询用于组合来自多个链接表的字段的交叉表版本。本地查询本身必须是可更新的,以便修改编辑表单上的数据。

现在我们计划用直通查询替换所有本地查询,以便直接使用本机 SQL Server 表。

我尝试使用以下 SQL 字符串创建一个名为 qrySelProductsPassThroughEditable 的非常简单的直通查询:

SELECT dbo.Products.ID, dbo.Products.Name FROM dbo.Products;

ID 字段是在 SQL Server 中定义为 Primary Key 的 IDENTITY 字段,定义如下:

CREATE TABLE [dbo].[Products](
    [ID] [int] IDENTITY(1,1) NOT NULL,
        ....
)

但是 Access 传递查询返回的数据表根本不可编辑。所以它也不能用作编辑表单的 .RecordSource 。

这与链接相反,该链接说,如果通路查询包含所有相关表的所有主键,则查询将是可编辑的。

结论增加了一个后验

通过下面的讨论,Microsoft Access 2007 .accdb、.accde 或 .accdr(Access 运行时)中的直通查询始终是只读的,永远不可编辑。您应该将其用作最终列表或报表的 .RecordSource,而不是用于必须使用链接表的表单或涉及数据 IO 链接表的可写普通查询。

4

4 回答 4

6

根据我上面的评论和 Yawar 的回答,我不知道传递查询是可编辑/可更新的。从某种意义上说,它们是可编辑的,您可以编辑保存的 Pass Through Query 对象,但我认为 Pass Through Query 不可能生成可编辑的记录集。

基本上有两种方法可以将 Access 连接到非 Access 数据源。

第一种方法,也是最流行的,是使用某种形式的链接表,通常是 ODBC 链接表。有多种方法可以通过 MS Access 使用 ODBC 链接表,但大多数开发人员更喜欢使用在应用程序启动时刷新或重建(删除和重新连接)的 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 记录集。ADO 是一种与 SQL Server 对话的好方法,因为它确实为您提供了很多控制权,但因为它的代码密集,而且因为 ODBC 链接表工作得很好,大多数开发人员不建议使用 ADO,除非没有其他方法可以做您想做的事情。一个例子是调用存储过程。我相信传递查询可以用来调用存储过程,但我也认为那里有一些限制(例如使用参数)。我相信在大多数情况下,开发人员使用 ADO 来调用存储过程。我经常使用 ADO,但我不经常使用存储过程(还没有),所以我没有很多关于这方面的信息。

值得一提的另一件事是,带有 ODBC 的 DAO 使用“延迟加载”,但 ADO 会强制您提取所有数据,如果您有超过数百万行,这可能非常耗时并消耗大量内存。否则,您将需要实现某种分页。

下面是我自己创建单个 DSN-Less ODBC 链接表的函数。如果您是 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、传递查询、SQL Server 等,您应该查看一些非常好的资源:

http://technet.microsoft.com/en-us/library/bb188204%28v=sql.90%29.aspx
http://www.utteraccess.com/wiki/Choosing_between_DAO_and_ADO

下面是一个将表单绑定到 ADO 记录集的示例。虽然这有点误导,因为最好有一个在应用程序运行时保持打开状态的全局连接对象。这允许您使用可自动更新的 ADO 记录集。使用这种做法还可能使您的记录集成为表单级对象。

http://msdn.microsoft.com/en-us/library/office/bb243828%28v=office.12%29.aspx

于 2013-09-19T21:43:58.053 回答
5

在 MsAccess 查询窗口中打开任何 SQL Server Select 语句(表、视图或具有许多连接表的 sql-select)并可以编辑/更新,有一种更简单的非文档化方法:

打开 Access 查询窗口并输入您的 SQL 语句。将表名替换为方括号内的 SQL Server 的完整 ODBC 字符串,后跟一个点以及架构和表名,如下例所示:

前:

SELECT SOH.SalesOrderID, SOH.OrderDate
FROM   Sales.SalesOrderHeader as SOH 

后:

SELECT SOH.SalesOrderID, SOH.OrderDate
FROM   [ODBC;Driver=SQL Server;Server=myServer;Database=AdventureWorks2012;Trusted_Connection=Yes;MarsConn=yes;].Sales.SalesOrderHeader as SOH 

查询现在是可更新的: Access Query Window 根据 SQL Select 语句显示来自 SQL Server 的数据

评论:

  • 并非每个 SQL 语句都使表或视图可更新。有关限制和限制,请参阅 CREATE VIEW (Transact-SQL) ( https://msdn.microsoft.com/en-us/library/ms187956.aspx ) 中的“可更新视图”部分。
  • 要在 Access 中更新的基础表必须具有时间戳或 RowVersion 列。
于 2015-09-03T11:18:21.873 回答
1

直通查询结果集不可编辑,但基于链接表的 Access 查询绝对是。

于 2013-09-19T19:05:34.480 回答
0

是的,“第二种方法是使用 ADO”确实如此,LinkMasterFields 和 LinkChildFields 属性在多表单中不起作用,并且 ADO 记录集在 Access 2013 报告中不起作用,所以我正在使用传递查询。我正在使用 ADP+ ADPX.accde 在多表单和多报告中模拟 LinkMasterFields 和 LinkChildFields 属性。

于 2014-09-14T13:50:03.780 回答