Access VBA Export to New CSV Run-time Error 3011 - vba

I have code that exports a dynamic query to a csv. First I save the sql to an existing query, updating it's sql. Then I use that as the query defs, provide saved specs, and want to export to a dynamically constructed csv file name. The csv doesn't exist yet, so I am creating it. I thought doing a docmd.transfertext acExportDelim would create the file.
I end up getting the following error:
Run-time error '3011':
The Microsoft Access database engine could not find the object 'filename.csv'.
Make sure it is spelled correctly. If 'filename.csv' is not a local object,
check your network connection or contact the server administrator.
The "filename.csv" in the error, is exactly what I construct in the below code, and the name of the csv file I want to be created by this process.
Private Sub cmdExportList_Click()
Dim fsql As String
Dim f As Form
Dim RS As DAO.Recordset
Dim MyDate As String
Dim args As String
Set f = Forms!frmMyLists.Form.frmMyLists_SubResults.Form
args = Nz(Forms!frmMyLists.Form.cboMyList.Value, "00")
fsql = "SELECT * " & _
"FROM tblVFileImport "
fsql = fsql & "WHERE tblVFileImport.ListName = '" & args & "' "
fsql = fsql & "ORDER BY tblVFileImport.ID"
CurrentDb.QueryDefs("qryListExportSpecs").SQL = fsql
MyDate = Format(Now(), "yyyymmdd")
If IsDev = True Then
vFile = "C:\LocalPath\VFileData\ExportList\" & args & MyDate & ".csv"
Else
vFile = "\\Server\Share\ExportList\" & args & MyDate & ".csv"
End If
DoCmd.TransferText acExportDelim, "MyListExportSpecs", "qryListExportSpecs", vFile, True
Application.FollowHyperlink vFile
MsgBox "All Set! " & args & " tagged list is now open in Excel. Have Fun!", vbOKOnly, "Export Complete"
End Sub
Right now, I am in my dev copy (IsDev = True) so I'm just going to that local path. I tried creating a csv with the name first, but if I don't write anything to it (which I don't want to, because I'm wanting to transfer the text to it) then it goes away when I close it. I am wondering if it does that because it's 0 bytes. Does anyone know what I am doing wrong? Thanks!
Edit:
I found that if I tested by creating the csv before running the code, so it would already exist, the code was deleting it. I researched that and found the export specs can sometimes mess things up. I removed the export specs and now it works!
So this is :
DoCmd.TransferText acExportDelim, "", "qryListExportSpecs", vFile, True

Related

Import CSV file to SQLITE database via VBA - Access

I have a project in Access VBA where I need to automate the import of the CSV file (MAX 15MB) into linked SQLITE db. All done on a local machine.
Something similar as for MS SQL (as written below) that would be achievable via query or VBA?
strConn = "DRIVER=ODBC Driver 13 for SQL Server;Server=" & serv & ";Database=" & databs & ";Uid=" & usern & ";Password=" & pwd & ";"
cn.Open strConn
Strsql1 = "BULK INSERT dbo.SEARCHUSRTABLE2 FROM '" & insertfile & "' WITH(FIELDTERMINATOR = ',',ROWTERMINATOR = '\n');"
Set rs = cn.Execute(Strsql)
Ok, we need a few things.
First up, we need from Access:
Browse to csv file – select
Import the csv file to a table.
Now, export to a SQLite.
But, we missing a few questions here.
First up, is the SQLite database the same database and in the same location all the time?
Have you installed the SQLite ODBC driver, and have you been able to link to SQLite from Access?
So, we kind of need the above all sorted out. Especially the connection to SQLite.
And it not clear if you plan/want to create a new table for each csv import, or you going to clear out a table, and re-fill?
Lets assume the following:
You have a linked table to SQLite working from Access.
You can click on this linked table in Access, and you can see/view and even edit the data FROM Access, but the database and table is of course a linked table to SQLite.
If all the above is working?
And ALL of the above so far takes ZERO code. So you “need” to get the above part working.
And we assume that each csv import is to create a new table in the SQLite database?
Then the code would look like this:
Paste this sub into a standard access code module.
Save it, and then with cursor anywhere in the code, hit f5 to run.
Sub CsvImportToSQL()
Dim strCsvFile As String
Dim f As Object
Set f = Application.FileDialog(3)
f.Filters.Clear
f.Filters.Add "Csv file", "*.csv"
If f.Show = False Then
' no file selected - quite
Exit Sub
End If
Dim strFromTable As String
strFromTable = f.SelectedItems(1)
Dim strTable As String
' get only name of file without extension for Access table name
strTable = Mid(strFromTable, InStrRev(strFromTable, "\") + 1)
strTable = Left(strTable, InStr(strTable, ".") - 1)
strTable = InputBox("Select table = " & strFromTable, "Inport to Access table", strTable)
If strTable = "" Then
' user hit cancel - exit
Exit Sub
End If
' transfer the table into access
DoCmd.TransferText acImportDelim, , strTable, strFromTable, True
' ok, now ask for table name to export to in SQLite
Dim strSQLiteTable As String
strSQLiteTable = strTable
strSQLiteTable = InputBox("Table name to export for SQLite", "SQL lite table name", strSQLiteTable)
If strSQLiteTable = "" Then
' user cancel - don't transfer - exit
Exit Sub
End If
' now transfer table to SQL site
Dim strCon As String
strCon = CurrentDb.TableDefs("Hotels").Connect
' (replace above Hotels with a KNOWN WORKING LINKED table to SQLite)
DoCmd.TransferDatabase acExport, "ODBC Database", strCon, acTable, strTable, strSQLiteTable
MsgBox "table exported to SQLITE"
End Sub

Command$() worked in Access 2007 but does not work in Access 2013

Items using:
Access 2013 Database Source is the .accdb (referenced as "Source")
Access 2013 Database .accde of the source. (referenced as "CurrentVersion")
The user has a copy of the CurrentVersion on their C:\AccessSystems folder (referenced as "UserVersion")
SQL Database table linked to "Source" named VersionControl2013.
Table contains: System_Name, Version_Number, MDE_Path_Name and MDE_Name.
The flow:
Developer makes a change in Source
Developer updates the Category to the next version number. Category is in the Databases properties.
Developer creates CurrentVersion and saves it to P:\ drive (where all the CurrentVersions are saved).
User opens UserVersion and code runs to check to see if it matches CurrentVersion.
User opts to update and code runs to close UserVersion and copy CurrentVersion to User's c:\AccessSystems folder.
Now... User is up to date with correct version.
UserVersion is opened by the user, on opening it checks to see if the version matches using below code:
Public Sub CheckVersionNumber()
Dim SQLConn As New ADODB.Connection
Dim AnswerSet As New ADODB.Recordset
Set dbs = CurrentDb
Set cnt = dbs.Containers!Databases
Set doc = cnt.documents!SummaryInfo
doc.Properties.Refresh
Set ThisVersion = doc.Properties("Category")
Set SystemName = doc.Properties("Title")
Set SQLConn = New ADODB.Connection
SQLConn.Provider = "sqloledb"
SQLConn.Open "Data Source=scgcserver1;Initial Catalog=SCGCDatawarehouse "
QueryString = "SELECT VersionControl2013.* FROM VersionControl2013 WHERE (((VersionControl2013.System_Name)=" & "'" & SystemName & "'" & "));"
AnswerSet.Open QueryString, SQLConn, , adCmdText
If AnswerSet.EOF = False Then
If RTrim(AnswerSet("Version_Number")) = ThisVersion Then
Else
MsgBox ("Version Number does not match")
ServDir = "p:\accesssytems"
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde"
Application.Quit
End If
End If
AnswerSet.Close
With SQLConn
.Close
End With
End Sub
Note: The code below works in Access 2007. It will not work in Access 2013.
When CurrentVersion is called and opened it runs the code below:
Public Function LoadVersion()
DialogMessage = "You have a previous version of the Application, Do you want to UPDATE your version?"
DialogStyle = vbYesNo + vbDefaultButton1
DialogTitle = "Update Application"
DialogResponse = MsgBox(DialogMessage, DialogStyle, DialogTitle)
If DialogResponse = vbYes Then
ApplicationName = Command$()
Call GetApplicationInformation
DoCmd.Hourglass True
ToDirectory = "C:\AccessSystems\" & RTrim(DatabaseName)
FromDirectory = RTrim(MDEPathName) & RTrim(DatabaseName)
FileCopy "p:\AccessSystems\compiles\Access2013Compiles\" & DatabaseName, "c:\AccessSystems\" & DatabaseName
MsgBox ("Your Client Copy has been updated - Thank You " & " " & ApplicationName & " " & DatabaseName)
Shell "MsAccess.exe " & "C:\AccessSystems\" & RTrim(DatabaseName)
Application.Quit
End If
End Function
Public Sub GetApplicationInformation()
Dim SQLConn As New ADODB.Connection
Dim AnswerSet As New ADODB.Recordset
Set SQLConn = New ADODB.Connection
SQLConn.Provider = "sqloledb"
SQLConn.Open "Data Source=scgcserver1;Initial Catalog=SCGCDatawarehouse "
QueryString = "SELECT VersionControl2013.* FROM VersionControl2013 WHERE (((VersionControl2013.System_Name)=" & "'" & ApplicationName & "'" & "));"
AnswerSet.Open QueryString, SQLConn, , adCmdText
If AnswerSet.EOF = False Then
DatabaseName = AnswerSet("MDE_Name")
MDEPathName = AnswerSet("MDE_Path_Name")
End If
AnswerSet.Close
With SQLConn
.Close
End With
End Sub
I get a runtime error
52: Bad file name or number.
Debug takes it to line and DatabaseName is "".
FileCopy "p:\AccessSystems\compiles\Access2013Compiles\" & DatabaseName, "c:\AccessSystems\" & DatabaseName
I feel the line: ApplicationName = Command$() has something to do with it because ApplicationName is blank also. It is supposed to bring in the application's name.
Why does it work in 2007, but not in 2013?
That's a rather convoluted system you have there.
The Command() function returns a string that was appended to the Access command line with the /cmd switch.
You'd have to launch Access e.g. like this
"MSACCESS.EXE C:\mypath\Database1.accdb /cmd SomeString"
then if Database1.accdb calls Command(), it returns "SomeString".
But if I understand you correctly, the upper code launches the lower code with
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde"
There is no /cmd switch, so Command() won't return anything.
Did it perhaps get lost in the switch to Access 2013?
EDIT:
As I wrote above, ApplicationName = Command$() cannot work in the lower code, because no /cmd string is passed here:
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde"
It is used here:
WHERE VersionControl2013.System_Name = " & "'" & ApplicationName & "'"
so you need to pass whatever is the correct VersionControl2013.System_Name, like this:
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde /cmd mySystemName"
Or if System_Name is simply the database (UserVersion) name, something like this:
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde /cmd " & Dir(CurrentDb.Name)
I used Dir() to extract the file name from the full path.
Perhaps I am not seeing all the code or missing something but... normally you need to declare DatabaseName as a public variable available to all subroutines.
Or .. pass the values back to the calling statement.
Call like this:
databasename = GetApplicationInformation()
The function would look like this:
Public Function GetApplicationInformation() As String
...
GetApplicationInformation = AnswerSet("MDE_Name") ' the database name
But of course this does not explain why it worked in Access 2007. perhaps some more detail from you would help.

How to limit the number of results in an LDAP query

I'm programming an Office 2010 Word template that needs to interact with the Active Directory, to retrieve some user info. The user filling out the template can give some input for the search that is used to retrieve the AD info.
I'm using the ADODB Recordset and Command to setup my query:
Public Function GetActiveDirectoryInfo(searchString As String) As Object
Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
Dim strQuery, adoRecordset
'remove user input asteriks
searchString = Replace(searchString, "*", "")
' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
strBase = "<LDAP://" & GLOBAL_LDAP_USER_OU & ">"
' Filter on user objects.
strFilter = "(&(objectCategory=person)(objectClass=user)(|(sn=" & searchString & "*)(cn=" & searchString & "*)))"
' Comma delimited list of attribute values to retrieve.
strAttributes = ACTIVE_DIRECTORY_FIELDS
' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";OneLevel"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 10
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
'adoCommand.Properties("Maximum Rows") = 10 'error: read only
On Error GoTo err_NoConnection
' Run the query.
Set adoRecordset = adoCommand.Execute
Set foundItems = adoRecordset
Debug.Print "Found : " & foundItems.RecordCount & " records"
Exit Function
err_NoConnection:
'in case of error: return <nothing>
Debug.Print Err.description
Set GetActiveDirectoryInfo = Nothing
End Function
THis function is part of a User Class in MS Word.
My question: how to prevent the user from retrieving thousands of records? I have been reading about paging, but that seems more like a network-load-thing than actually limiting the search results that will eventually get back to me.
I've tried several things but with no results. For instance setting the MaxRecords or Maximum Rows properties. Both give an error (non existing property for the first, and read only error for the second).
ANy ideas anyone.
MS Office 2010 dutch
ADO Objects 6.0
Thanx!
Unfortunately ADO MaxRecord that limits the number of search results is not implemented for ADsDSObject. The link https://support.microsoft.com/kb/269361 details the workaround to solve the issue.

How to locate a rogue SELECT statement in an Access frontend?

I have two version of my access frontend. One for Access 2003 which is still being run by a few computers not yet upgraded to Access2010 and Win7, the Acces2010 version unfortunately is caused in Access crash in 2003 at close of the mainform that I have been unable to fix. Backend is SqlServer 2005 SqlExpress version.
Therefore I am stuck with the older frontend for 2003 people, who fortunately don't need the newer capabilities in 2010 version.
Now, a maintenance utility which loads data from a mainframe dump is getting blocked by a "SELECT 1 on Patient_Clinic_Visits" when the Access 2003 version is running somewhere. What I can't find, is where that "SELECT 1 on Patient_Clinic_visits" is coming from.
I have looked in all the module code, and all the queries, but can't find anything like that.
I assume it must therefore be in the frontend form, but how do iI search that without looking through all the objects and controls of that form for RecordSource with some SQL code in it?
cheers,
JonHD
In the end I searched some other questions and thought about programmatically dumping the likely offending information. This is my concoction of two different answers to do what I want. Do to the limits of the Instant Window in VBA over how many lines it will keep from a Debug.Print, I have used WScript object to dump to a log file.
The code basically:
opens each form in the database in turn
dumps its RecordSource description
then for each control on its form, dumps relevant information that MAY contain SQL in some way
note: I use the fact that a Writeline (some code) that causes and error will fail and not write to avoid a lot of testing for different control types for which properties to dump or not dump.
then closed the forms
then it goes through all the queries in the database, and dumps SQL code
(Note1: in the end this didn't find the answer to my problem - see my other recent question!!)
(Note2: this was a quick and dirty script. I noticed the first time it ran the WriteStream didn't write anything, even though it on Step ing through the code it seemed to be doing something. Anyhow when I ran it again it worked. Haven't taken the time to debug why!).
Function DumpFormsAndQueries()
Dim obj As AccessObject
Dim objctrl As Control
Dim frm As Form
Dim dbs As Object
Dim fsoSysObj As FileSystemObject
Dim filFile As Object
Dim txsStream As TextStream
Dim strPath As String
Set dbs = Application.CurrentProject
Set fsoSysObj = New FileSystemObject
' Return Windows Temp folder.
strPath = "C:\Temp\"
On Error Resume Next
' See if file already exists.
Set filFile = fsoSysObj.GetFile(strPath & "Database_Form_dump.Log")
' If not, then create it.
If Err <> 0 Then
Set filFile = fsoSysObj.CreateTextFile(strPath & "Database_Form_dump.Log")
End If
Debug.Print ">> dumping to: " & strPath & "Database_form_dump.log"
Set txsStream = filFile.OpenAsTextStream(ForAppending)
For Each obj In dbs.AllForms
DoCmd.OpenForm obj.name, acDesign
Set frm = Forms(obj.name)
Debug.Print ">>>> dump form: " & obj.name
txsStream.WriteLine "====================================================================="
txsStream.WriteLine "Form : " & obj.name
txsStream.WriteLine "RecordSource: " & frm.RecordSource
txsStream.WriteLine "====================================================================="
For Each objctrl In frm.Controls
txsStream.WriteLine " --------------------------------------------------"
txsStream.WriteLine " : " & objctrl.name & " Type = " & TypeName(objctrl)
txsStream.WriteLine " --------------------------------------------------"
On Error Resume Next
txsStream.WriteLine " >>>> Recordsource: (" & objctrl.RecordSource & ")"
txsStream.WriteLine " >>>> Controlsource: (" & objctrl.ControlSource & ")"
txsStream.WriteLine " >>>> Rowsource: (" & objctrl.RowSource & ")"
txsStream.WriteLine " >>>> Caption: (" & objctrl.Caption & ")"
txsStream.WriteLine " >>>> Text: (" & objctrl.Text & ")"
txsStream.WriteBlankLines 1
Next objctrl
DoCmd.Close acForm, obj.name, acSaveNo
txsStream.WriteBlankLines 3
Next obj
txsStream.WriteLine "====================================================================="
txsStream.WriteLine " Q U E R I E S - in database"
txsStream.WriteLine "====================================================================="
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb()
For Each qdf In db.QueryDefs
txsStream.WriteLine "Query: " & qdf.name
txsStream.WriteLine "SQL (start) ---------------------------------------------------- "
txsStream.WriteLine qdf.sql
txsStream.WriteLine "SQL (end) ---------------------------------------------------- "
Next qdf
Set qdf = Nothing
Set db = Nothing
txsStream.Close
Debug.Print ">> ended"
End Function
In Access menu select Database Tools->Database Documenter. There, select all objects and push OK. It will take some time, but then you will be presented with a report that lists everything in your database, including the code at the end.
The report could be quite big for big databases.
You can export the report to Word (there is an option for it). There, search for your string. (I think it should be "SELECT 1 from Patient_Clinic_visits")

VB piping STDOUT from cmd.exe output to to write to textbox

I'm trying to adapt a VBscript that runs the QWINSTA command against a text file I've defined as an array and displays the results in a text file.
after looking at numerous examples on Stack and other sites this is my latest iteration, that displays everything except the STDOUT, which is really what I'm after, not sure if it's an issue with how I'm calling the command piping the output or what. I'm also passing two variables as arguments to complicate matters :)
The Text file that stdout is piped to is empty after the FOR Loop completes
I may be going the long way about this, most of my past experience with this is in BATCH
For Each server In RemotePC
'The Query is launched
Dim Query As New ProcessStartInfo
Query.WorkingDirectory = "c:\"
Query.Arguments = server & " " & profile & " >C:\Windows\Temp\SFOUT.txt"
Query.FileName = "QWINSTA"
Query.WindowStyle = ProcessWindowStyle.Hidden
Process.Start(Query)
'Call Shell("QWINSTA /SERVER:" & server & " " & profile & " >C:\Windows\Temp\SFOUT.txt", vbHidden, Timeout:=5000)
Dim SFOUT As New IO.StreamReader("C:\windows\temp\SFOUT.txt")
'Results are Echoed to TextboxResults
TextBoxResults.Text &= "__________________________________________________________" & ControlChars.CrLf
TextBoxResults.Text &= server & ControlChars.CrLf
TextBoxResults.Text &= SFOUT.ReadToEnd & ControlChars.CrLf
SFOUT.Close()
Next
Here is what the working code in VBscript looks like
For Each server In RemotePC
Dim WshShell, oExec
Set WshShell = CreateObject("WScript.Shell")
Set StrDir = "QWINSTA /SERVER:" & server & " " & profile
'The Query is launched
Set oExec = WshShell.Exec(StrDir)
'We wait for the end of process
Do While oExec.Status = 0
WScript.Sleep 500
Loop
'We scan and only display the command output of commands without NULL output
Do While oExec.StdOut.AtEndOfStream <> True
Results.WriteLine("__________________________________________________________")
Results.WriteLine(server)
Results.WriteLine oExec.StdOut.ReadLine
Loop
NEXT
Any help is appreciated
#Nilpo
this is what I get back
SESSIONNAME USERNAME ID STATE TYPE DEVICE
console Matt 1 Active
I've built something similar to this using QWINSTA and piping the output in batch and it works flawlessly, just having issues adapting this.
here's the last thing I tried I tried to simplify things by calling something as basic as notepad.exe, and even trying to define the environment variable thinking it's not reading %PATH%, in reply to #Nilpo
Dim Query As New Process
Query.StartInfo.FileName = "notepad.exe"
'Query.StartInfo.Arguments = server & " " & profile & " >C:\Windows\Temp\SFOUT.txt"
Query.StartInfo.UseShellExecute = False
Query.StartInfo.RedirectStandardOutput = True
Query.StartInfo.WindowStyle = ProcessWindowStyle.Normal
Environment.SetEnvironmentVariable("PATH", "%PATH%;" & "C:\Windows\System32\notepad.exe")
Query.Start()
You should have a space after the output redirection.
Query.Arguments = server & " " & profile & " >C:\Windows\Temp\SFOUT.txt"
Should be
Query.Arguments = server & " " & profile & " > C:\Windows\Temp\SFOUT.txt"
That being said, the only thing I can see that may not work is here.
Query.WorkingDirectory = "c:\"
Query.Arguments = server & " " & profile & " >C:\Windows\Temp\SFOUT.txt"
Query.FileName = "QWINSTA"
Query.WindowStyle = ProcessWindowStyle.Hidden
Process.Start(Query)
I'm not sure that you can use arguments in this fashion. Your output redirection is being read as a literal argument when it's really not. In a command line environment it's interpreted as a separate command, not an argument to the first command. It's very similar to piping in that manner. Supplying this as an argument in your code probably won't work as expected. You may want to go back to the Call Shell method. That will execute the command as if it were on the command line.
[Edit]
I was correct. Here is the proper way to do this using your method.
Query.WorkingDirectory = "c:\"
Query.Arguments = server & " " & profile & " >C:\Windows\Temp\SFOUT.txt"
Query.FileName = "QWINSTA"
Query.WindowStyle = ProcessWindowStyle.Hidden
'Redirect output
Query.UseShellExecute = False
Query.RedirectStandardOutput = True
Process.Start(Query)
'Read the output
Dim output As String = Process.StandardOutput.ReadToEnd
' wait for the process to terminate
Process.WaitForExit