I am attempting to import data into my MS Access project via TransferText, but am receiving error #3051: "The Microsoft Access database engine cannot open or write to the file ''. It is already opened exclusively by another user, or you need permissions to view and write its data."
It is odd to me that the filename given in the error message is blank. I have checked and rechecked the file name, even to perform a check "If Not fso.FileExists(file_name) Then ... End If" prior to the TransferText call.
I have also checked and rechecked the table name and the file permissions. The table is successfully emptied before the TransferText call, so I know that works. The file is in a subfolder relative to the Access database file in a folder on my desktop. I have not set or unset any permissions for any of the folders or files.
Until now I had been using DoCmd.TransferSpreadsheet to import the data that is downloaded from a web based tool, but I found Excel was misinterpreting some alphanumeric codes as numbers in scientific format, such as 1E100 would become 1E+100 in the Excel file, so the data was corrupted before getting to the Access database. These codes are getting corrupted in uncorrectable ways, so I can't modify the data after import. I found I could save the data from the web tool as a CSV file rather than an Excel file; this led me to try to use DoCmd.TransferText.
Below is the code I am using:
Private Function ImportExcel( _
ByVal file_name As String, _
ByVal table_name As String _
) As Integer
On Error GoTo Error
Dim fso As FileSystemObject, folder_name As String
Dim xl_book As Excel.Workbook
Dim xl_sheet As Excel.Worksheet
Dim i As Integer
' suppress excel's file-not-found popup
Set fso = New FileSystemObject
If Not fso.FileExists(file_name) Then
ImportExcel = -1
GoTo Finish
End If
' gets a workbook from a global application object
Set xl_book = Util.GetExcelWorkbook( _
file_name:=file_name, _
visible:=False, _
use_cache:=True _
)
If xl_book Is Nothing Then
ImportExcel = -1
GoTo Finish
End If
' always use the first worksheet
Set xl_sheet = xl_book.Sheets(1)
' fake the first record to force columns types
xl_sheet.range("A2").EntireRow.Insert
For i = 1 To xl_sheet.UsedRange.columns.count
xl_sheet.Cells(2, i) = "test"
Next i
' make sure the table is closed
DoCmd.Close _
ObjectType:=acTable, _
ObjectName:=table_name, _
Save:=acSaveNo
' link to file
DoCmd.SetWarnings False
If ".csv" = Right(file_name, 4) Then
' empty table
DoCmd.RunSQL "DELETE * FROM " & table_name, True
' import data
Debug.Print table_name
Debug.Print file_name
DoCmd.TransferText _
TransferType:=acImportDelim, _
SpecificationName:=table_name & " Import Spec", _
TableName:=table_name, _
FileName:=file_name, _
HasFieldNames:=True
Else
' delete table
On Error Resume Next
DoCmd.DeleteObject _
ObjectType:=acTable, _
ObjectName:=table_name
If 0 <> Err.Number Then
Resume Next
End If
On Error GoTo Error
' import data
DoCmd.TransferSpreadsheet _
TransferType:=acImport, _
TableName:=table_name, _
FileName:=file_name, _
HasFieldNames:=True, _
range:=xl_sheet.NAME() & "!" & _
xl_sheet.range( _
xl_sheet.Cells(1, 1), _
xl_sheet.Cells( _
xl_sheet.UsedRange.rows.count, _
xl_sheet.UsedRange.columns.count _
) _
).Address(RowAbsolute:=False, ColumnAbsolute:=False), _
SpreadsheetType:=acSpreadsheetTypeExcel9
End If
DoCmd.SetWarnings True
Finish:
Set xl_sheet = Nothing
If Not xl_book Is Nothing Then
xl_book.Close SaveChanges:=False
End If
Set xl_book = Nothing
Set fso = Nothing
Exit Function
Error:
Resume Finish
End Function
The two Debug.Print calls just prior to the DoCmd.TransferText call print exactly what is expected.
Related
I'm writing a VBA code to add files, which are into several folders, into a ZIP file.
This procedure should run automatically, by a scheduled job, and I try to add a parameter to force "yes to all".
In Microsoft support there are some constants but if I add to my code, I don't have the aspected result.
the code is the following
Public Sub ZipFolder(ZipFileName As Variant, _
FolderPath As Variant, _
Optional ByVal FileFilter As String, _
Optional ByVal Overwrite As Boolean = False)
Dim fso As Object, tf As Object
Dim strZIPHeader As String, sFile As String
On Error GoTo done
' create zip file header
strZIPHeader = Chr(80) & Chr(75) & Chr(5) & Chr(6) & String(18, Chr(0))
With CreateObject("Shell.Application")
sFile = Dir(FolderPath, vbNormal)
Do Until sFile = vbNullString
.Namespace(ZipFileName).CopyHere FolderPath & sFile, **"&H10&"**
sFile = Dir
Loop
End With
Set fso = Nothing
Set tf = Nothing
done:
If Err.Number <> 0 Then MsgBox Err.Description, vbApplicationModal + vbInformation
End Sub
The parameter &H10& doesn't work. I have tried with "&0X14&" as well but same result.
Any idea?
Thank you
You can study the article and full code here on exactly this subject:
Zip and unzip files and folders with VBA the Windows Explorer way
You'll see, that shall the file be overwritten, it is simply deleted before proceeding:
If FileSystemObject.FileExists(ZipFile) Then
If Overwrite = True Then
' Delete an existing file.
FileSystemObject.DeleteFile ZipFile, True
' At this point either the file is deleted or an error is raised.
Else
ZipBase = FileSystemObject.GetBaseName(ZipFile)
' Modify name of the zip file to be created to preserve an existing file:
' "Example.zip" -> "Example (2).zip", etc.
Version = Version + 1
Do
Version = Version + 1
ZipFile = FileSystemObject.BuildPath(ZipPath, ZipBase & Format(Version, " \(0\)") & ZipExtension)
Loop Until FileSystemObject.FileExists(ZipFile) = False Or Version > MaxZipVersion
If Version > MaxZipVersion Then
' Give up.
Err.Raise ErrorPathFile, "Zip Create", "File could not be created."
End If
End If
End If
I have an MS Access 2010 Database that has a table that is linked to a CSV file. Upating the CSV files location using the inbuilt Access "Linked Table Manager" doesn't work.
I check the file i want to update, choose "always prompt for new location" and select the new file. I get a message telling me that the update was successful, but when I go to check, the table is still linked to the old file.
Is this a MS Access bug and if so what is the most efficient workaround?
I ended up deleting the old table and manually recreating a new table with the same specifications.
*Updated: -- I forgot to include the referenced Function Relink_CSV :(
Yes, I would call it a bug. Microsoft probably calls it a 'design characteristic'.
As you have discovered, you can manually fix the issue. If you are interested in a code solution, then I may have something that will work for you -- if your CSV file is delimited by comma's.
The following code (which you need to modify!) will delete the existing linked csv file, then add a link to the same file. For debugging, my code then deletes that link and adds a link to a different file name, but in the same folder.
There are other solutions that make use of a saved Import Specification, that you can reuse, if your csv format is not simple.
Option Explicit
Option Compare Database
Sub Call_Relink()
Dim dbs As DAO.Database
Dim tdf As DAO.TableDef
Dim strTableName As String
Dim strPath As String
Dim strFile As String
Dim iReply As Integer
iReply = MsgBox("WARNING!!!! This code will remove the linked tables 'FileA' and 'FileB'" & vbCrLf & vbCrLf & _
"Click 'Yes' to Continue" & vbCrLf & "Click 'No' to Stop", vbYesNo, "CAUTION!! Will remove linked table(s)")
If iReply <> vbYes Then
Exit Sub
End If
On Error GoTo Error_Trap
Set dbs = CurrentDb
dbs.TableDefs.Delete "FileA" ' For testing; delete table if it already exists
strPath = "C:\Temp\"
strFile = "FileA.csv"
strTableName = "FileA" ' Table name in Access
Relink_CSV strTableName, strPath, strFile ' Call function to link the CSV file
dbs.TableDefs.Refresh ' Refresh TDF's
Debug.Print "Pause here and check file link" ' Put a breakpoint here; pause and look at the table in Access
dbs.TableDefs.Delete "FileA" ' For testing; delete table if it already exists
strPath = "C:\Temp\" ' Path to next csv
strFile = "FileB.csv" ' Name of next csv file
strTableName = "FileA" ' Table name in Access
Relink_CSV strTableName, strPath, strFile ' Call function to link to a different CSV file
dbs.TableDefs.Refresh
Debug.Print "Pause here and check file link" ' Put a breakpoint here; pause and look at the table in Access
My_Exit:
Set dbs = Nothing
Exit Sub
Error_Trap:
Debug.Print Err.Number & vbTab & Err.Description
If Err.Number = 3265 Then ' Item not found in this collection.
' Ignore this error
Resume Next
End If
MsgBox Err.Number & vbTab & Err.Description
Resume My_Exit
Resume
End Sub
Function Relink_CSV(strTableName As String, strPath As String, strFile As String)
' (1) Name of the table in Access
' (2) Path to the file
' (3) File name
On Error GoTo Relink_Err
DoCmd.TransferText acLinkDelim, , strTableName, strPath & strFile, False, ""
Relink_Exit:
Exit Function
Relink_Err:
Debug.Print Err.Number & vbTab & Err.Description
MsgBox Err.Number & vbTab & Err.Description
Resume Relink_Exit
Resume
End Function
I'm trying to export the results of a dynamic SQL statement but keep getting the error 3027 "Cannot update. Database or object is read-only.". I'm using Access 2003. GetYearFromDirName(sFolder) is parsing out a year from a directory structure and using that as a calculated column in the SQL results.
Here is the code in question:
sSQL = "SELECT INDEXDB1.IFIELD1 AS TestArea, INDEXDB1.IFIELD2 AS TSID, INDEXDB1.IFIELD3 AS MapCoord, " _
& "INDEXDB1.IFIELD4 AS Community, INDEXDB1.IFIELD5 AS Address, INDEXDB1.IFIELD6 AS DocNum, " _
& "'" & GetYearFromDirName(sFolder) & "' AS Yr FROM INDEXDB1;"
'DoCmd.TransferSpreadsheet acExport, , sSQL, sFolder & "\" & BoxNum & ".csv"
'DoCmd.OutputTo acOutputQuery, "ExportRecs", acFormatXLS, sFolder & "\" & BoxNum & ".csv"
SaveToExcel sSQL, sFolder & "\" & BoxNum & ".csv"
Calls:
Public Sub SaveToExcel(strSQL As String, strFullFileName As String)
Dim strQry As String
Dim db As Database
Dim Qdf As QueryDef
On Error GoTo SaveToExcel_err
strQry = "TempQueryName"
Set db = CurrentDb
'Set Qdf = db.CreateQueryDef(strQry, strSQL)
'DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel8, strQry, strFullFileName, True
'DoCmd.DeleteObject acQuery, strQry
With db
' Create permanent QueryDef.
Set Qdf = .CreateQueryDef(strQry, strSQL)
' Open Recordset and print report.
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel3, strQry, strFullFileName, True
' Delete new QueryDef because this is a demonstration.
.QueryDefs.Delete Qdf.Name
.Close
End With
Exit Sub
SaveToExcel_err:
MsgBox Error & " " & Err & " in sub SaveToExcel. Close program and start over."
End Sub
Is there a better way to export dynamic SQL statement results? In the end, I need a CSV file.
You may open it in Excel, but CSV is a text format, so you need to use DoCmd.TransferText instead of DoCmd.TransferSpreadsheet. Manually go through the export once using the Export Data Wizard. As you do so, you'll wand to create and name a Export Specification. This will specify commas as the delimiter and double quotes as text delimiters. The name of the export spec you created is passed as the second argument to TransferText.
I have a piece of code, which imports a spreadsheet when the database is opened. Originally I had the path for the spreadsheet coded in, but the path is subject to change when the spreadsheet version is changed. The most up to date path is now stored in a global parameters table. I can't get the code to work with a variable, maybe I'm doing something stupid, I don't know, I'm fairly new to VB/VBA.
Function Import_Menu()
Dim db As DAO.Database
Set db = CurrentDb
Dim mpath As String
mpath = DLookup("MenuPath", "Global", "ID = 1")
On Error Resume Next: db.TableDefs.Delete "Activity_Menu": On Error GoTo 0
db.TableDefs.Refresh
DoCmd.TransferSpreadsheet _
TransferType:=acImport, _
SpreadsheetType:=acSpreadsheetTypeExcel9, _
TableName:="Activity_Menu", _
FileName:=" & mpath & ", _
HasFieldNames:=False, _
Range:="Task Menu!A3:AF120"
db.TableDefs.Refresh
db.Close: Set db = Nothing
End Function
This;
FileName:=" & mpath & ", _
results in the string & mpath & which is not correct.
If mpath is a full path and file name:
FileName:= mpath, _
If its just a path:
FileName:= mpath & "\BLA.BLOOP", _
(Ensuring you add a \ if needed)
I have an import specification for csv files which, when I run it on a file through the GUI, works just fine. However, when I run it through VBA, for some reason it forgets that one column is supposed to be a Text column and makes it a Number column instead, thereby causing tons of errors.
My code is below. It works in the sense that everything runs properly, but for some reason the import specification for the CSVs does not run properly. The meaningless case switch is a place holder, as I will need to add more types of reports after I get the first working.
Sub ImportDE(Folder As Object)
Dim db As DAO.Database
Dim names As DAO.Recordset
Dim Files As Object, file As Object, SubFolders As Object, subfolder As Object
Dim ExString As Variant
Dim check As Boolean
Dim FileChange As String
Set db = CurrentDb
On Error Resume Next: db.TableDefs.Delete "tblImport": On Error GoTo 0
db.TableDefs.Refresh
Set names = CurrentDb.OpenRecordset("SELECT Old FROM DENames")
Set Files = Folder.Files
Set SubFolders = Folder.SubFolders
For Each subfolder In SubFolders
ImportDE subfolder
Next
With names
Do While Not .EOF
ExString = .Fields(0)
For Each file In Files
If InStr(file.Type, "Worksheet") > 0 Then
If InStr(file.Path, ExString & ".xls") > 0 Then
DoCmd.TransferSpreadsheet _
TransferType:=acImport, _
SpreadsheetType:=acSpreadsheetTypeExcel9, _
TableName:="tblImport_" & ExString, _
filename:=file.Path, _
HasFieldNames:=True, _
Range:="A:CT"
db.TableDefs.Refresh
End If
ElseIf InStr(file.Type, "Comma Separated") > 0 Then
If InStr(file.Path, ExString & ".csv") > 0 Then
Select Case ExString
Case "Usage"
DoCmd.TransferText _
TransferType:=acImportDelim, _
SpecificationName:=UsageCSV, _
TableName:="tblImport_" & ExString, _
filename:=file.Path, _
HasFieldNames:=True
db.TableDefs.Refresh
End Select
End If
End If
Next
.MoveNext
Loop
End With
db.Close: Set db = Nothing
End Sub
Am I missing something obvious? Why doesn't the import spec work properly?
The TransferText SpecificationName parameter is supposed to be a string expression. Since the code does not declare a variable named UsageCSV, I'm guessing that is the literal name of the specification. If that's correct, enclose the name in double quotes.
DoCmd.TransferText _
TransferType:=acImportDelim, _
SpecificationName:="UsageCSV", _
TableName:="tblImport_" & ExString, _
filename:=file.Path, _
HasFieldNames:=True
At the top of your code module After Option Compare Database
Add Option Explicit.
This will require all of your variable to be declared and you will never have this issue again