Автоматически обновлять серверную часть SQL Server с ежедневно обновляемой таблицей доступа

#sql-server #ms-access #vba #odbc #dsn

#sql-сервер #ms-access #vba #odbc #dsn

Вопрос:

Резюме: У меня есть локальная база данных Access, которая содержит заказы и обновляется ежедневно утром автоматической процедурой VBA, запускаемой задачей Windows. Более подробно, каждый день будут добавляться новые заказы, а существующие заказы будут обновляться новой информацией с использованием локального .csv файла, который будет удален в среду общей папки в 5:30 утра.

Теперь у меня есть SQL Server, который должен быть обновлен и точная копия локальной таблицы, в лучшем случае сразу после локального обновления. Это необходимо, потому что я использую SQL Server в качестве серверной части для инструмента автоматической рассылки заказов, который в будущем будет использоваться примерно 50 сотрудниками.

Что я пробовал: я запускаю процедуру локального обновления полностью в локальной таблице, которая является и всегда будет локальной, чтобы обеспечить плавный процесс обновления. Чтобы обновить таблицу SQL, я попытался реализовать это, создав связанную таблицу, однако наборы данных не передаются на SQL Server. Это странно, потому что, когда я вручную изменяю отдельные поля в связанной таблице, изменения немедленно отражаются в таблице SQL Server. На сервере SQL не обновляются только процессы на основе VBA.

Код:

 Sub Sync_SQL()

Dim myDB As DAO.Database
Set myDB = CurrentDb

Dim strSQL As String

Dim qdf As QueryDef

' Erstellt einen temporären Query mit einem ODBC-Connection String zur Verbindung mit dem SQL Server
Set qdf = CurrentDb.CreateQueryDef("SyncDB")
qdf.Connect = "ODBC;Driver={SQL Server};server=XX.X.XXX.XX;database=OPM;uid=USID;pwd=PWD;"

' Löscht alle noch offenen Aufträge aus dem SQL-Server
qdf.SQL = "DELETE FROM [OPM].[dbo].[ReiseMaster] WHERE NOT [Name of Employee] = '---------';"
qdf.ReturnsRecords = False

' Führt den Query aus und misachtet dabei jegliche Dialogfelder
DoCmd.SetWarnings False
DoCmd.OpenQuery "SyncDB"
DoCmd.SetWarnings True

' Fügt aktuell offene Aufträge in den SQL-Server ein
myDB.Execute "INSERT INTO [dbo_ReiseMaster] SELECT * FROM [ReiseMaster] WHERE NOT [Name of Employee] = '---------';"

' Leert den Statistik-Table (sollte in Zukunft anders funktionieren)
qdf.SQL = "DELETE FROM [OPM].[dbo].[Statistics];"
qdf.ReturnsRecords = False

' Führt den Query aus und misachtet dabei jegliche Dialogfelder
DoCmd.SetWarnings False
DoCmd.OpenQuery "SyncDB"
DoCmd.SetWarnings True

' Lädt den Statistik-Table mit den neuen Werten hoch (sollte in Zukunft nur noch für neue Aufträge erfolgen, um Performance auch nach längerer Laufzeit der Datenbank gering zu halten)
myDB.Execute "INSERT INTO [dbo_Statistics] SELECT * FROM [Statistics];"

' Setzt die aktive Verbindung zurück und löscht den temporären Query
Set qdf = Nothing
myDB.QueryDefs.Delete "SyncDB"
myDB.QueryDefs.Refresh

End Sub
  

Результат: В частности, следующие изменения в связанной таблице не будут отражены в SQL Server:

 myDB.Execute "INSERT INTO [dbo_ReiseMaster] SELECT * FROM [ReiseMaster] WHERE NOT [Name of Employee] = '---------';"
  

Хотя связанная таблица dbo_ReiseMaster в файле Access содержит обновленные значения, они не загружаются на SQL Server.

Как я могу гарантировать, что локальная таблица Access (в каких бы вариантах я ни манипулировал данными) всегда будет передавать изменения на SQL Server?

Комментарии:

1. Вы проверили в запросе Access, что часть ВЫБОРА SELECT * FROM [ReiseMaster] WHERE NOT [Name of Employee] = '---------'; фактически возвращает записи?

2. Привет, Андре, да, я это проверил. В основном имеется 10 000 записей с фактическим именем сотрудника, и они возвращаются с использованием этого оператора. Я также только что заметил, что на самом деле нет вставки в связанную таблицу dbo_ReiseMaster . Для тестирования я удалил все записи с именем в связанной таблице и выполнил эту инструкцию выше. Хотя часть ВЫБОРА возвращает мне запись, я не могу найти эти данные в связанной таблице.

3. Хм, попробуйте myDB.Execute "INSERT ...", dbFailOnError получить информацию об ошибке.

4. Связан ли dbo_ReiseMaster с Access с помощью ODBC-соединения? Или вы каждый раз подключаетесь вручную с помощью VBA?

5. dbo_ReiseMaster подключен через ODBC-соединение, поэтому он должен быть постоянно подключен.

Ответ №1:

Вы не можете использовать один объект подключения, а затем «надеяться», что access знает, какую таблицу использовать. Вы выполняете sql для одного объекта connection, поэтому таблицы insert и source будут находиться в этом одном удаленном соединении. Вы не можете этого сделать.

Что бы произошло, если бы исходная таблица существовала на стороне sql Server?

Однако сбросьте все эти данные о соединении с запросом. Просто свяжите таблицы с сервером.

Теперь вы можете писать и использовать стандартный sql из access и использовать обе таблицы так, как если бы они были локальными.

Итак, вы можете использовать: dim strSQL как строку

 strSQL = "INSERT INTO [ReiseMasterLinked] " amp; _
        "SELECT * FROM [ReiseMaster] WHERE NOT [Name of Employee] = '---------';"

currentdb.Execute strSQL
  

Таким образом, вы можете использовать sql для двух таблиц, даже если одна из них связана с sql Server, но вы должны использовать связанные таблицы. Вы не имеете дело с объектом connection, не видите и не используете его, поскольку он всегда будет применяться к одному объекту connection. Однако Access является ОЧЕНЬ особенным в том смысле, что вы можете написать sql, который включает связанные таблицы и локальные таблицы, и это разрешит соединение, на котором основаны две таблицы (или фактически, что одна таблица не связана, является локальной, а другая — связанной таблицей.

Редактировать

Вот еще один пример. Но ОБРАТИТЕ ВНИМАНИЕ, как я прокомментировал .Выполнить команду и заменить ее docmd.RunSQL.

 Sub AppendTest()

  Dim strSQL     As String
  
  strSQL = "INSERT INTO tblHotelsSQL " amp; _
           "SELECT * FROM tblHotelsLOCAL WHERE NOT tblHotelsLOCAL.HotelName = '-----'"

  'CurrentDb.Execute strSQL, dbFailOnError
  DoCmd.RunSQL strSQL
  
End Sub
  

Это выполняется медленнее и завершает команду транзакцией, поэтому вы можете ответить «да» или «нет» на приглашение, но выдает ГОРАЗДО более подробное сообщение об ошибке, объясняющее, почему запрос не удалось выполнить или не выполнялся. И снова обратите внимание, что строки подключения не требуются. Чтобы все вышеперечисленное сработало, можно быстро дважды щелкнуть связанную таблицу с SQL Server, чтобы убедиться, что все связанные таблицы работают нормально (и если в ней отображаются данные — возможно, попробуйте отредактировать одну строку — отключите, и это обеспечит чтение / запись связанной таблицы.

Комментарии:

1. Хорошо, я понимаю, на что вы указываете. Учитывая это объяснение, мой ожидаемый результат на самом деле не был определенным. Однако я не уверен, что вы имеете в виду, говоря «Просто связать таблицы с сервером»., потому что я на самом деле использую ссылку (Импорт>> Ссылка). dbo_ReiseMaster это связанная таблица, и именно поэтому я попытался выполнить эту таблицу, поскольку это обычная таблица доступа, как показано в моем коде выше.

2. Ах, хорошо, тогда вы можете на 100% отказаться от любых «подключений» в своем коде. Вы можете использовать встроенный sql или изменить существующий запрос, но этот запрос будет стандартным запросом — нет необходимости использовать строку подключения в коде.

3. смотрите мое новое редактирование предложение в моем посте — оно дает вам некоторые вещи для тестирования / пробы. Как только вы получите docmd.RunSQL, работающий нормально, затем измените код на CurrentDb.Execute — это избавит от транзакции и запроса «да / нет» для фактического выполнения обновления.