1

我正在尝试使用 MS Access 对我无法控制的 ODBC 服务器进行更新。我必须使用 Passthrough 的原因是我正在访问的记录有超过 255 个字段(如果可以的话,我会使用链接表)。

我一直在使用此资源通过 Passthrough ( http://www.techonthenet.com/access/tutorials/passthrough/basics09.php )获取数据

查询很简单:SELECT FullName, PointNumber FROM DNP3.CDNP3AnalogIn

ODBC 连接字符串是: ODBC;DSN=SCX6_DB;LOCATION=Main;UID=admin;PWD=password;LOCALTIME=False;

现在在 Access 数据库中,我有一个表(SCADA DB 标记)与字段(FullName,PointNumber)的名称相同,我想使用 Update Passthrough 查询更新 ODBC 数据库中的字段,但我不确定该怎么做这个。

我将之前的查询保存为 DNP3_CDNP3AnalogIn 查询,并尝试创建一个新查询:

UPDATE [DNP3_CDNP3AnalogIn Query] INNER JOIN [SCADA DB Tags] ON 
[DNP3_CDNP3AnalogInQuery].FullName = [SCADA DB Tags].FullName 
SET [DNP3_CDNP3AnalogIn Query].[PointNumber] = [SCADA DB Tags].[PointNumber];

但我从 Access 收到错误消息:Operation must use an updateable query.

我知道有办法做到这一点,但我似乎找不到一个例子(我可能没有在谷歌上搜索正确的短语)。微软页面(http://technet.microsoft.com/en-us/library/bb188204%28v=sql.90%29.aspx)说:There is, however, one important limitation: the results returned by SQL pass-through queries are always read-only. If you want to enable users to perform updates based on the data retrieved, you must write code to handle this.不幸的是它没有给出一个例子!

谁能给我一个解决方案,如果需要,我可以使用 VBA 吗?如果需要,我还可以提供更多背景信息。不幸的是,我不是 Access 方面的专家,我只是想提出一个可以节省我一些时间的自动化解决方案。

4

2 回答 2

2

当他们说“如果你想让用户能够基于从传递查询中检索到的数据执行更新,你必须编写代码来处理这个”,他们的意思可能是这样的:

Option Compare Database
Option Explicit

Public Sub UpdateSqlServer()
    Dim cdb As DAO.Database, rst As DAO.Recordset
    Dim con As Object  ' ADODB.Connection
    Dim cmd As Object  ' ADODB.Command
    Const adParamInput = 1
    Const adInteger = 3
    Const adVarWChar = 202

    Set cdb = CurrentDb
    Set rst = cdb.OpenRecordset( _
            "SELECT " & _
                "[SCADA DB Tags].FullName, " & _
                "[SCADA DB Tags].PointNumber " & _
            "FROM " & _
                "[DNP3_CDNP3AnalogIn Query] " & _
                "INNER JOIN " & _
                "[SCADA DB Tags] " & _
                    "ON [DNP3_CDNP3AnalogIn Query].FullName = [SCADA DB Tags].FullName", _
            dbOpenSnapshot)

    Set con = CreateObject("ADODB.Connection")
    con.Open "DSN=SCX6_DB;"
    Set cmd = CreateObject("ADODB.Command")
    cmd.ActiveConnection = con
    cmd.CommandText = _
            "UPDATE DNP3.CDNP3AnalogIn SET " & _
                "PointNumber=? " & _
            "WHERE FullName=?"
    cmd.Parameters.Append cmd.CreateParameter("?", adInteger, adParamInput)  ' PointNumber
    cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255)  ' FullName
    cmd.Prepared = True

    Do Until rst.EOF
        cmd.Parameters(0).Value = rst!PointNumber
        cmd.Parameters(1).Value = rst!FullName
        cmd.Execute
        rst.MoveNext
    Loop
    Set cmd = Nothing
    con.Close
    Set con = Nothing
    rst.Close
    Set rst = Nothing
    Set cdb = Nothing
End Sub

笔记:

  1. 该代码使用您现有的 ODBC DNS。
  2. 它使用 Prepared Statement 来执行更新,提高效率并防止与 SQL 注入相关的故障。
  3. 源 Recordset 对传递查询执行 INNER JOIN,以确保代码仅尝试更新服务器上实际存在于服务器上的行。
于 2014-01-29T10:45:28.313 回答
1

您是说 [DNP3_CDNP3AnalogIn Query] 是基于服务器端的,而表 [SCADA DB Tags] 是基于本地的吗?在这种情况下,您不能使用传递查询。

但是,由于表位于不同的位置,通过不能同时接触两者。

但是,您可以在循环中执行“单个”服务器端(通过)。如果您设置传递查询并保存它,则此代码将起作用:

  Dim qdfPass       As DAO.QueryDef

  Dim rstLocal      As DAO.Recordset
  Dim strSQL        As String
  Dim strSQL2       As String

  Set qdfPass = CurrentDb.QueryDefs("MyPass")

  strSQL = "UPDATE [DNP3_CDNP3AnalogIn Query] " & _
           "SET [DNP3_CDNP3AnalogIn Query].[PointNumber] = 'xxxx' " & _
           "WHERE [DNP3_CDNP3AnalogInQuery].FullName = 'zzzz' "

  Set rstLocal = CurrentDb.OpenRecordset("[SCADA DB Tags]")

  Do While rstLocal.EOF = False
     strSQL2 = Replace(strSQL, "xxxx", rstLocal!PointNumber)
     strSQL2 = Replace(strSQL2, "zzzz", rstLocal!FullName)
     qdfPass.SQL = strSQL2
     qdfPass.Execute
     rstLocal.MoveNext
  Loop

  rstLocal.Close
于 2014-01-29T19:25:50.757 回答