VBA only exports partial recordset - vba

The following code is linked to my access database and exports one column from the table to a txt file, however, it randomly stops on a specific record and won't export the rest of the file:
Sub ExportTxtFiles()
Dim rst As DAO.Recordset
Open "\\...Export Files\ZM.txt" For Output As #1
Set rst = CurrentDb.OpenRecordset("tbl_temp", dbOpenSnapshot)
If rst.RecordCount > 0 Then
rst.MoveFirst
Do Until rst.EOF
Print #1, rst!ID
rst.MoveNext
Loop
End If
rst.Close
Set rst = Nothing
End Sub
Table has 347 lines and stops halfway through the number in line 304.

You never close the file. Files are buffered, so VBA is free to wait for more to be planned to be written, and only write that when the buffer is full or the file is closed.
Close the file with the Close statement:
Close #1
However, I strongly recommend not relying on Print for files. Instead, use DoCmd.TransferText acExportDelim, it's generally faster and Print has some quirks

Related

Looping through all items in a MS Access Table and using each as input for a function

I am trying to figure out the best (an most efficient) way to loop through each record in my MS Access table and use a column of data as an input parameter for a another function.
Please see the code I was using below:
Public Sub FL()
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("codes")
'Check to see if the recordset actually contains rows
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst 'Unnecessary in this case, but still a good habit
Do Until rs.EOF = True
'Save CPT code into a variable
CPT = rs!CPT
CMS_Util.psps_util_json ("CPT")
'Move to the next record. Don't ever forget to do this.
rs.MoveNext
Loop
Else
MsgBox "There are no records in the recordset."
End If
MsgBox "Finished looping through records."
rs.Close 'Close the recordset
Set rs = Nothing 'Clean up
End Sub
I pulled this code off SO and tried to modify it by my public sub CMS_Util.psps_util_json is not running at all. The loop of saving each CPT in the variable works fine and the CMS_Util.psps_util_json runs perfect when ran alone.
I believe my first mistake is using a Do Unitl loop versus a For Each loop but I hit a wall in what I could find.
FYI, the function that it is calling is designed to pull data from an API on CMS.gov and then calls another function that parses the JSON. I do not think that will effect the solution but I wanted to provide all the context I had. Thanks!
Working with large sets of data in applications slows down execution tremendously. Rather read the data to an array and work with the data in the array
Something like this :
Dim Data_Arry as variant
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("codes")
Data_Array = rs.GetRows(rs.RecordCount)
Then work with data in the array, You should be able to assign back using the same logic
PS - I am not sure if my syntax above is correct.

Attempting to output a SQL developer export to Excel by running a batch file

I'm new to running tasks through batch files. I have a batch and sql script that outputs to csv, which works. But I want the output to be in Excel. I've edited these scripts so that it can output in Excel. The proces does create an Excel file. However when I attempt to open the Excel file, I get an error that the file has not been found. What am I doing wrong?
This is the SQL script. Let's say this is stored in file.sql :
set verify off
set define off
set termout off
set heading off
set pages 50000
set feedback off
set newpage none
set trimspool on
set linesize 1000
set decimal
whenever sqlerror exit
spool C:\pathname\filename.xlsx append
select
''
||COLUMN_1||
';'||COLUMN_2||
';'||COLUMN_3||
''
FROM blahblah.tablename;
spool off
exit
This is the batch script:
echo off
if exist C:\pathname\filename.xlsx del C:\pathname\filename.xlsx
:: creating a header
echo COLUMN_1;COLUMN_2;COLUMN_3;
sqlplus blahblah/password#databasename #C:\pathname\file.sql
I've basically just changed the .csv file extension in the scripts to a .xlsx extension but clearly this isn't enough, because I can't open the file.
Also, how do I just select all (select *) through this proces? I've tried changing that too, but I just ended up with no data at all (not even a csv file)
In Excel VBA:
Sub ImportData()
Dim Conn as New Connection
Conn.Connectionstring = ' get details from here https://www.connectionstrings.com/sql-server/ depending on version of sql you are using
conn.open
dim rs as new recordset
rs.open "Select * from BlahBlahTablename",conn
if not rs.eof then ' if we have data
range("a2").copyfromrecordset rs
end if
Dim f as field
dim r as range
for each f in rs.fields
r = f.name
set r = r.offset(0,1)
next f
rs.close
set rs = nothing
conn.close
End Sub
This assumes a reference to ado in excel

VBA in MS Access: how to accelerate a loop operation on a recordset

In a database under my maintenance (MS Access 2010) I use a VBA procedure for cleaning up records, concretely: setting values in a field from "yes" to "no". The procedure loops through all records and sets the values in the respective field as required.
My database has about 900 records so far. Not too many, one should think.
My problem: the VBA procedure operates very slowly. On my current machine I have to wait for about 10 seconds until the loop has gone through the 900 records. That's impractical in everyday work.
What I need: I am looking for ways to speed this up, either through improvements to the code, or through a completely different approach.
Here is my procedure:
Private Sub WipeSelectionMarks_Click()
'Remove any filter that might be set to reduce the number of records in
'the form - We want here to operate on all records in the database!
Me.Filter = ""
Me.FilterOn = False
'Don't know if we really need two commands here; but at least it works
'Operate on a recordset that holds all the records displayed in the form
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
rs.MoveFirst
Do Until rs.EOF
With rs
.Edit
!Int_IwSelectMove = False
.Update
End With
rs.MoveNext
Loop
'Message box with info what has been done
MsgBox "A total of " & rs.RecordCount & " records were updated by wiping the Move mark"
'Cleaning up
Set rs = Nothing
Me.Refresh
End Sub
Note 1: if a solution would be using an SQL command instead, I will be grateful for practical hints or examples. I use SQL commands at many places, still, getting put on the right track here would be helpful.
Note 2: Or can the VBA procedure be rewritten in a way that only records where the field in question has value "yes" are processed (these are usually only 20-30 of the 900), and those with "no" are left out?
You can use the UPDATE command:
CurrentDb.Execute "UPDATE YourTable SET Int_IwSelectMove = False"
can the VBA procedure be rewritten in a way that only records where
the field in question has value "yes" are processed
Indeed, and that may very well be the fastest method, as you will not have to requery the form:
With rs
Do Until .EOF
If !Int_IwSelectMove.Value = True Then
.Edit
!Int_IwSelectMove = False
.Update
End If
.MoveNext
Loop
.Close
End With
Or you could use FindFirst or a filtered recordset. Running SQL on the recordset of a form is usually the last option.

What happens if you use .BeginTrans and don't use .CommitTrans or .Rollback

What happens if you use .BeginTrans and .Execute then you exit code before .CommitTrans or .Rollback in Access VBA.
Daniel's comment pretty much sums it up. When I run the following code...
Sub noCommit()
Dim cdb As DAO.Database, rst As DAO.Recordset
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset("tblSampleData", dbOpenTable)
DBEngine.Workspaces(0).BeginTrans
rst.Edit
rst!Item = "Item1amended"
rst.Update
'' no Commit and no Rollback
End Sub
...and then open the table in Datasheet view any attempts to edit either of the two records results in a "beep" and the "no entry" icon on the record selector.
Attempts to add a new record are met with a "Could not update" error:
So, the changes made within the transaction are not written, and the table is left in a locked state until the connection is closed (or the transaction is cleared). Since my transaction was based on the default Access connection (DBEngine.Workspaces(0)) that means either closing and re-opening Access, or running the following:
Sub transRollback()
DBEngine.Workspaces(0).Rollback
End Sub

Rookie SQL inside of VB question - MSAccess 2003

Hey guys, can anyone help me with a simple question. I have this SQL statement below in a sub in VB within access from a button click, and I am new to this.
Here is what I typed:
Private Sub Command0_Click()
Dim rs As Recordset
Dim sql As String
Dim db As Database
Set db = CurrentDb
sql = "SELECT * FROM Transactions"
Set rs = db.OpenRecordset(sql)
Do Until rs.EOF
rs.MoveNext
Loop
If Not rs.EOF Then
MsgBox "test"
End If
End Sub
Ok, so how do I populate this?? Essentially I am justing starting out with this, so I am wondering how do I take this simple code, and run it like a query so that the resulting recordset opens.
Thanks!
some other remarks and advices:
1) Always indicate which type of recordset you are using. Here it seems to be a DAO recordset, so go for a complete declaration like:
Dim rs as DAO.recordset
Runing on another computer, and depending on the declaration order of ADODB and DAO libraries, the very same code can generate a bug.
2) To avoid any disturbing error message if no record is available, you can add an extra test, something like
if rs.recordcount = 0 then
Else
rs.moveFirst
....
3) To browse the complete recordset with debug.print, you could do it this way. Just ad a 'm_debugLine' as string, and a 'fld' as DAO.Field in your declarations.
rs.MoveFirst
do while not rs.eof
m_debugLine = ""
for each fld in rs.fields
m_debugLine = m_debugLine + vbTab + fld.value
next fld
debug.print m_debugLine
rs.movenext
loop
4) you could even add a debug.print line to print out the field names before printing the data. I guess you'll find this one
Depending on what you are trying to do, you may be over-complicating this. A better approach would be to set the recordsource of the form (in the property sheet) to the transactions table then drop the fields you want on the form using the visual designer.
HOWEVER, If you really must do it this way, here is the code that will replace what you have and open a spreadsheet like view of the data in the transactions table.
Private Sub Command0_Click()
docmd.Opentable "transactions"
End Sub
If you want to limit the results to a query, then first build the query and save it then use the following code.
Private Sub Command0_Click()
docmd.OpenQuery "MyQueryName"
End Sub
To be extremely literal, your original code DID populate a recordset (in the rs object). You can access the fields by name using code in your while loop such as
debug.print rs("Field1")
You put your code inside the Do..Loop. This code will be evaluated for each record that is encountered.
Do Until rs.EOF
Msgbox "The value for MyField is " & rst!MyField
rs.MoveNext
Loop
you get at the columns of the record for the recordset like rs(0) or rs("columnname")....
if your transactions table has three columns named a, b, c you could get to it like:
rs(0)
rs(1)
rs(2)
or
rs("a")
rs("b")
rs("c")