I recently came across this question, and some of the things that I come across in the answers here are simply incorrect:
- CANNOT compactly and restore access database through VBA when it is opened! Regardless of whether all tables are closed, if you have an exclusive lock, etc.
- You can, however, compile the backend from the linked database if all connections to it are closed. That is why Tony Tows was able to successfully compress and recover.
This is unfortunate, and the simplest solution is to create a linked database. But if this is undesirable, there is one alternative thing that you can do if you are willing to do some kind of strange deception.
The problem is that the main database must be closed while the compression and repair is in progress. To get around this, we can do the following:
- Programmatically create a VBScript file
- Add code to this file so that we can compress and restore our database without opening it
- Open and run this file asynchronously
- Close our database before compression and recovery occurs.
- Compactness and restoration of the database (creating a copy), deleting the old one, renaming the copy
- Let's open our database, continue the package
- Delete newly created file
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 dbe = WScript.CreateObject(""DAO.DBEngine.120"")" & 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 & _ "Set app = CreateObject(""Access.Applition"")" & 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
These are all the steps described above, and resumes the package by calling the ResumeBatch function in the database that called this function (without any parameters).
Please note that actions such as click protection and antivirus / policies that vbscript files do not like can ruin this approach.
source share