Обновление сквозного запроса MS Access

Я пытаюсь обновить сквозной запрос, используя MS Access, на сервер ODBC, над которым я не контролирую. Причина, по которой я должен использовать сквозную передачу, заключается в том, что записи, к которым я обращаюсь, имеют более 255 полей (если бы я мог, я бы использовал связанную таблицу).

Я использовал этот ресурс для получения данных с помощью Passthrough (http://www.techonthenet.com/access/tutorials/passthrough/basics09.php)

Запрос простой: SELECT FullName, PointNumber FROM DNP3.CDNP3AnalogIn

ODBC Connect Str: ODBC;DSN=SCX6_DB;LOCATION=Main;UID=admin;PWD=password;LOCALTIME=False;

Теперь внутри базы данных Access у меня есть таблица (теги SCADA DB) с тем же именем для полей (FullName, PointNumber), и я хочу обновить поля внутри базы данных 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.

Я знаю, что есть способ сделать это, но я не могу найти пример (возможно, я не ищу правильную фразу). Страница Microsoft (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, я просто пытаюсь придумать автоматизированное решение, которое могло бы сэкономить мне время.


person reubenb87    schedule 28.01.2014    source источник


Ответы (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. Он использует подготовленный оператор для выполнения обновлений, повышая эффективность и защищая от сбоев, связанных с внедрением SQL.
  3. Исходный набор записей выполняет INNER JOIN для сквозного запроса, чтобы убедиться, что код пытается обновить только те строки на сервере, которые фактически существуют на сервере.
person Gord Thompson    schedule 29.01.2014
comment
Спасибо за подробный ответ. Я получаю сообщение об ошибке в cmd.Execute (диспетчер драйверов Microsoft ODBC: тип данных SQL вне допустимого диапазона). Я предполагаю, что это из-за отправки неправильного типа для PointNumber. Из схемы базы данных: PointNumber — это слово (беззнаковое). Я не совсем уверен, как сделать это приведение вместо Integer, как вы поставили? - person reubenb87; 30.01.2014
comment
На самом деле проблема связана с полем FullName, так как это строка, в которой есть '.' и '' символы. Если я жестко кодирую запрос на обновление с примером FullName, он работает, например, WHERE FullName='this is. тестовое полное имя». Но если я инкапсулирую ? подобно '?' (ГДЕ FullName='?') это не работает. Любые подсказки? - person reubenb87; 30.01.2014
comment
Исправлена ​​проблема с полем FullName, использовал adVarChar вместо adVarWChar и все работает!!! Огромное спасибо! Я только хочу, чтобы ошибки возвращались там, где их немного легче отлаживать. - person reubenb87; 30.01.2014

Вы говорите, что [DNP3_CDNP3AnalogIn Query] основан на стороне сервера, а эта таблица [Теги БД SCADA] — на локальной основе? В этом случае вы не можете использовать сквозной запрос.

Однако, поскольку таблицы НАХОДЯТСЯ в разных местах, проход не может касаться ОБА одновременно.

Однако вы можете выполнять «одну» серверную часть (проходную) в цикле. Если вы настроите сквозной запрос и СОХРАНИТЕ его, то этот код будет работать:

  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
person Albert D. Kallal    schedule 29.01.2014