Access - 使用链接表更新本地表(但没有主键)

Posted

技术标签:

【中文标题】Access - 使用链接表更新本地表(但没有主键)【英文标题】:Access - Update local table with linked table (but without primary key) 【发布时间】:2019-06-19 10:13:23 【问题描述】:

我有一个小的 ACCESS 工具,我想在其中读取链接表并更新本地表。导入新条目就像一种魅力,但是当我尝试更新现有条目时,它总是会引发异常(运行时错误 3073)。

这是我的代码

Sub UpdateBLPNR()
With CurrentDb
    Set tdf = .CreateTableDef("ext_BEL_PLZ")
    tdf.Connect = "ODBC;DSN=EasyProd PPS;DataDirectory=PATH;SERVER=NotTheServer;Compression= ;DefaultType=FoxPro;Rows=False;Language=OEM;AdvantageLocking=ON;Locking=Record;MemoBlockSize=64;MaxTableCloseCache=5;ServerTypes=6;TrimTrailingSpaces=False;EncryptionType=RC4;FIPS=False"
    tdf.SourceTableName = "BEL_PLZ"
    .TableDefs.Append tdf
    .TableDefs.Refresh
End With

Dim SQLUpdate As String
Dim SQLInsert As String
SQLUpdate = "UPDATE BEL_PLZ " & _
            "INNER JOIN ext_BEL_PLZ " & _
            "ON(BEL_PLZ.NR = ext_BEL_PLZ.NR) " & _
            "SET BEL_PLZ.BEZ = ext_BEL_PLZ.BEZ "
SQLInsert = "INSERT INTO BEL_PLZ (NR,BEZ) " & _
            "SELECT NR,BEZ FROM ext_BEL_PLZ t " & _
            "WHERE NOT EXISTS(SELECT 1 FROM BEL_PLZ s " & _
            "WHERE t.NR = s.NR) "
DoCmd.SetWarnings False
DoCmd.RunSQL (SQLUpdate)
DoCmd.RunSQL (SQLInsert)
DoCmd.SetWarnings True

DoCmd.DeleteObject acTable, "ext_BEL_PLZ"
End Sub

已经发现 Access 在使用链接表更新本地表时可能会遇到一些问题,但我无法找到解决方法。

(SQLInsert 正在工作,SQLUpdate 正在杀死我)

这是我的最终解决方案(感谢 ComputerVersteher)-->

Sub UpdateBLPNR()
'Define Variables
Dim SQLUpdate As String
Dim SQLInsert As String
Dim qdf As DAO.QueryDef
'Create temporary table and update entries
With CurrentDb
    Set tdf = .CreateTableDef("ext_BEL_PLZ")
    tdf.Connect = "ODBC;DSN=EasyProd PPS;DataDirectory=PATH;SERVER=NotTheServer;Compression= ;DefaultType=FoxPro;Rows=False;Language=OEM;AdvantageLocking=ON;Locking=Record;MemoBlockSize=64;MaxTableCloseCache=5;ServerTypes=6;TrimTrailingSpaces=False;EncryptionType=RC4;FIPS=False"
    tdf.SourceTableName = "BEL_PLZ"
    .TableDefs.Append tdf
    .TableDefs.Refresh
     With .OpenRecordset("SELECT ext_BEL_PLZ.NR, ext_BEL_PLZ.BEZ " & _
                        "FROM ext_BEL_PLZ INNER JOIN BEL_PLZ ON BEL_PLZ.NR = ext_BEL_PLZ.NR", dbOpenSnapshot)
        Set qdf = .Parent.CreateQueryDef("")
        Do Until .EOF
             qdf.sql = "PARAMETERS paraBEZ Text ( 255 ), paraNr Text ( 255 );" & _
                       "Update BEL_PLZ Set BEL_PLZ.BEZ = [paraBEZ] " & _
                       "Where BEL_PLZ.NR = [paraNr]"
             qdf.Parameters("paraBez") = .Fields("BEZ").Value
             qdf.Parameters("paraNr") = .Fields("NR").Value
             qdf.Execute dbFailOnError
             .MoveNext
        Loop
    End With
End With
'Run SQL Query (Insert)
SQLInsert = "INSERT INTO BEL_PLZ (NR,BEZ) " & _
            "SELECT NR,BEZ FROM ext_BEL_PLZ t " & _
            "WHERE NOT EXISTS(SELECT 1 FROM BEL_PLZ s " & _
            "WHERE t.NR = s.NR) "
DoCmd.SetWarnings False
DoCmd.RunSQL (SQLInsert)
DoCmd.SetWarnings True
'Drop temporary table
DoCmd.DeleteObject acTable, "ext_BEL_PLZ"
End Sub

【问题讨论】:

正确,要么更新条目,要么插入新条目 然后删除加入更新!这导致只读。使用子选择。 或者导入表(不是链接),创建pk,更新。 如何将内连接换成子选择方式? (想继续使用链接表) 避免DoCmd尤其是SetWarnings False,无知不是幸福;),使用On Error Resume Next和Err对象来决定警告是否重要。 【参考方案1】:

从只读表创建记录集以获取值。

Dim qdf As DAO.QueryDef
With CurrentDb
    With .OpenRecordset("SELECT ext_BEL_PLZ.NR, ext_BEL_PLZ.BEZ " & _
                        "FROM ext_BEL_PLZ INNER JOIN BEL_PLZ ON BEL_PLZ.NR = ext_BEL_PLZ.NR", dbOpenSnapshot)
        Set qdf = .Parent.CreateQueryDef(vbNullString)
        qdf.SQL = "PARAMETERS paraBEZ Text ( 255 ), paraNr Long;" & _
                       "Update BEL_PLZ Set BEL_PLZ.BEZ = [paraBEZ] " & _
                       "Where BEL_PLZ.NR = [paraNr]"
        Do Until .EOF
             qdf.Parameters("paraBez") = .Fields("BEZ").Value
             qdf.Parameters("paraNr") = .Fields("NR").Value
             qdf.Execute dbFailOnError
             .MoveNext
        Loop
    End With
End With

【讨论】:

参数类型匹配表字段? BEL_PLZ.Bez 少于或等于 255 个字符? 是的,“Bez”总是少于 255 个字符,因为我们的刨削软件有一些限制【参考方案2】:

你不能这样做。

Access 本身以外的其他数据源上的链接表需要一个主键来支持更新。

通过 GUI 进行链接时,Access 允许您指定一个备用键,如果没有主键,但如果有一个应该是您的主键,则该键唯一地标识行。

【讨论】:

据我所知,链接表中没有主键(它是一个非常古老的 dbf 数据库,但不幸的是我们无法在 2020 年之前切换到 SQL 数据库)。我的想法是使用 VBA 链接表,复制/更新本地表并取消链接表。我必须避免对链接表进行任何更改,因为它将被另一个部门访问和更改。 然后从制作表的完整副本开始,不要执行涉及链接表的更新。就这么简单。 正确,我有一个本地表,从链接表中导入 2 列,然后更新或创建本地表中的条目,并出于安全原因断开链接表 如果表只有这两列,另一种方法可能是:使用DELETE 查询删除已经出现的行,然后使用插入查询插入所有行。如果有其他列您希望不受影响,那当然不是一种选择。 顺便说一句,我打开了一个关于这个on Access UserVoice的问题。这是 Access 数据库引擎的常见限制性限制,并且经常会产生问题。

以上是关于Access - 使用链接表更新本地表(但没有主键)的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Access 希望您识别链接表上的主键?

MS Access:来自 SQL Server 的只读链接表?

MS Access 2007 - 导入表后,记录集不再可更新

使用主键复制 Access 表

从 MS Access 链接 Oracle 视图时可以指定主键吗?

更新 Access 链接表以使用 UNC 路径