Я недавно наткнулся на этот вопрос, и некоторые вещи, с которыми я сталкиваюсь в ответах, просто неверны:
- Вы НЕ МОЖЕТЕ компактировать и восстанавливать базу данных доступа через VBA, пока она открыта! Не имеет значения, все ли таблицы закрыты, есть ли у вас эксклюзивная блокировка и т. Д.
- Однако вы можете сжать серверную часть из связанной базы данных, если все подключения к ней закрыты. Вот почему Тони Тьюс мог успешно уплотнять и ремонтировать.
Это прискорбно, и самый простой обходной путь - создать связанную базу данных. Но если это нежелательно, есть одна альтернативная вещь, которую вы можете сделать, если вы готовы сделать какой-то странный обман.
Проблема в том, что основная база данных должна быть закрыта, пока происходит сжатие и восстановление. Чтобы обойти это, мы можем сделать следующее:
- Программно создать файл VBScript
- Добавьте код в этот файл, чтобы мы могли сжимать и восстанавливать нашу базу данных, не открывая ее
- Открыть и запустить этот файл асинхронно
- Закройте нашу базу данных, прежде чем произойдет сжатие и восстановление
- Сжатие и восстановление базы данных (создание копии), удаление старой, переименование копии
- Повторно открыть нашу базу данных, продолжить пакет
- Удалить только что созданный файл
Public Sub CompactRepairViaExternalScript()
Dim vbscrPath As String
vbscrPath = CurrentProject.Path & "\CRHelper.vbs"
If Dir(CurrentProject.Path & "\CRHelper.vbs") <> "" Then
Kill CurrentProject.Path & "\CRHelper.vbs"
End If
Dim vbStr As String
vbStr = "dbName = """ & CurrentProject.FullName & """" & vbCrLf & _
"resumeFunction = ""ResumeBatch""" & vbCrLf & _
"Set app = CreateObject(""Access.Application"")" & vbCrLf & _
"Set dbe = app.DBEngine" & vbCrLf & _
"Set objFSO = CreateObject(""Scripting.FileSystemObject"")" & vbCrLf & _
"On Error Resume Next" & vbCrLf & _
"Do" & vbCrLf & _
"If Err.Number <> 0 Then Err.Clear" & vbCrLf & _
"WScript.Sleep 500" & vbCrLf & _
"dbe.CompactDatabase dbName, dbName & ""_1""" & vbCrLf & _
"errCount = errCount + 1" & vbCrLf & _
"Loop While err.Number <> 0 And errCount < 100" & vbCrLf & _
"If errCount < 100 Then" & vbCrLf & _
"objFSO.DeleteFile dbName" & vbCrLf & _
"objFSO.MoveFile dbName & ""_1"", dbName" & vbCrLf & _
"app.OpenCurrentDatabase dbName" & vbCrLf & _
"app.UserControl = True" & vbCrLf & _
"app.Run resumeFunction" & vbCrLf & _
"End If" & vbCrLf & _
"objFSO.DeleteFile Wscript.ScriptFullName" & vbCrLf
Dim fileHandle As Long
fileHandle = FreeFile
Open vbscrPath For Output As #fileHandle
Print #fileHandle, vbStr
Close #fileHandle
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
wsh.Run """" & vbscrPath & """"
Set wsh = Nothing
Application.Quit
End Sub
Это делает все шаги, описанные выше, и возобновляет пакет, вызывая функцию ResumeBatch
в базе данных, которая вызывала эту функцию (без каких-либо параметров).
Обратите внимание, что такие вещи, как защита "нажми и работай" и антивирус / политика, которой не нравятся файлы VBScript, могут разрушить этот подход.