Does ADO Recordset need to be closed? - vbscript

I have an ADO recordset (not ADO.NET) that I populate in every iteration of a loop.
My question is: Do I need to close the recordset at end of every iteration so it gets populated with fresh data in next iteration OR I could just use the unclosed recordset to populate with new data in next iteration. Please look at code sample below.
set rs=Server.CreateObject("ADODB.recordset")
for count = 0 to 3
rs.Open "Select * from Customers where CustomerId = " & count, conn
'do some processing of data in recordset
'rs.Close 'NOT VERY SURE IF I NEED TO DO THIS
next

You cannot open a recordset again :
Error 3705 : Operation is not allowed when the object is open
So given the sample above which requires a different selection of data, you must close the recordset.

Related

Anyway to iterate quickly over a collection of UDTs?

Let's say I have a collection of UDTs. I populate it as below:
public type udtEmp
Id as long
Name as string
end type
dim col as new Collection
dim empRec as udtEmp, empDummy as udtEmp
for n = 1 to 100000
empRec = empDummy ' reset record
emp.Id = n
emp.Name = "Name " & n
col.add emp, cstr(emp.Id)
next
Now I want to loop through it. I am using a Long data type as the index to .Item()
dim n as long
For n = 1 To 100000
emp = col.Item(n)
Next
The code above works, but it's really slow - takes 10,000 milliseconds to iterate. If I accessed the collection via a key, its much faster - 78 milliseconds.
For n = 1 To 100000
emp = col.Item(cstr(n))
Next
The problem is that when I iterate over collection, I don't have the keys. If I had a collection of objects instead of UDTs, I could do for each obj in col, but with UDTs, it won't let me iterate in that manner.
One of my thoughts was to have a secondary collection of indexes and keys to point to the main collection, but I am trying not to complicate the code unless I absolutely have to.
So what are my options?
the elegance of the code or the performance of it is a serious decision you have to make. the choice should be based on the impact of the results. for each is elegant but slow and goes with objects and classes. but if the speed is a mater then use UDT and arrays.
in your case, i think an array of UDT is best suited for your situation. and to gain more speed , try to access arrays using SAFE_ARRAY (that you can google for it), the result is much impressive.
You can use a user typed class collection. It'll provide the for-each iteration ability with great performance.
Easiest way to make that happen is through the Class Builder Utility (https://msdn.microsoft.com/en-us/library/aa442930(v=vs.60).aspx). You might need to first run the Add-in Manager and load the Class Builder Utility. (I think that there were install options regarding these features when you installed vb6/vs6? So if you don't see the Class Builder Utility in the Add-in manager it's could be due to that).
To match your udt sample, using the Class Builder Utility, first add a class (eg: Employee), with two properties (eg: EmpId and EmpName, long and string types respectively). Then add a collection (eg: Employees) based on the Employee class. Save it to the project (that will create two new class modules) and close the Utility.
Now you can create the new Employees collection, load it up, and iterate through it via index, key or for-each. (note: don't use a pure number for the key - requesting an item by a key that is a pure number, even as a string, will be interpreted as an index request, it'll be slow and you probably won't get the desired item)
Also - once the new classes have been created, you can add customized properties and methods to them to handle whatever kinds of fancy stuff you may have requirements for.
Dim i As Long
Dim Emp As Employee
Dim colEmp As New Employees
Dim name As String
' Loading
For i = 1 To 100000
colEmp.Add i, "name" & CStr(i), "key" & CStr(i)
Next i
' iterate with index
For i = 1 To 100000
Set Emp = colEmp(i)
name = Emp.EmpName
Next i
' iterate with key
For i = 1 To 100000
Set Emp = colEmp("key" & i)
name = Emp.EmpName
Next i
'iterate with for-each
For Each Emp In colEmp
name = Emp.EmpName
Next Emp
Timings
On my system for the above code:
Loading time: 1 second
Index time: 20 seconds
Key time: 0.29 seconds
For-each time: 0.031 seconds

Access word documents header containing a table with vbscript

I need to read the pure text values from cells of a table located in the page header of a word document using vbscript.
All i could achieve until now is to read some kind of text from the header by this:
wscript.echo WordApp.ActiveDocument.Sections(1).Headers(1).Range.FormattedText.Text
But how can i gain access to the table object and read each cell value?
Tables in Word documents can be enumerated via the Tables collection.
For Each tbl In WordApp.ActiveDocument.Sections(1).Headers(1).Range.Tables
For i = 1 To tbl.Rows.Count
For j = 1 To tbl.Columns.Count
WScript.Echo tbl.Cell(i, j).Value
Next
Next
Next

"Multiple- Step operation generated errors. check each status value." error in VB6 Application

when I try to insert a value to recordset in the 'Description' field. it showing a error like
runtime error '-2147217887(80040e21)'
Multiple- Step operation generated errors. check each status value.
sql = "SELECT * FROM vePODetail WHERE vePOID=" & Str(ado_veReceive.Recordset("vePOID")) & " ORDER BY vePODetailID"
rs.ActiveConnection = g_cnnCompany
rs.Open sql
Do While Not rs.EOF
ado_veReceiveDetailWF.Recordset.AddNew
ado_veReceiveDetailWF.Recordset("vePODetailID") = rs("vePODetailID")
ado_veReceiveDetailWF.Recordset("prMasterID") = rs("prMasterID")
ado_veReceiveDetailWF.Recordset("Description") = rs("Description")
ado_veReceiveDetailWF.Recordset("QuantityReceived") = rs("QuantityOrdered") -rs("QuantityReceived")
ado_veReceiveDetailWF.Recordset.Update
rs.MoveNext
Loop
rs.Close
the field in the recordset acccepts only 50 char.
Please tell how to increase the size/length of the field in the recordset.
If the field is 50 chars long, you must change the DB's definition of the field from 50 to whatever you need. You cannot do that through a recordset
Assuming you're using SQL Server, you can change your query using a CAST operation:
sql = "SELECT vePODetailID,prMasterID,CAST(Description as VARCHAR(100)) AS Description, QuantityReceived FROM vePODetail WHERE vePOID=" & Str(ado_veReceive.Recordset("vePOID")) & " ORDER BY vePODetailID"
That should set the length of the Description field in the recordset to 100 characters. You can do this in other db platforms as well, but the syntax may be different for the CAST.

VB6 Recordset "Open" taking more time to show result as compared to backend

I am using a query to find data.
Same query taking less time i.e 2 sec to execute from backend.
But in code same query taking more time i.e 30 sec in recordset.open.
Database : Sybase
Thanks
Code Sample :
Dim rsRoute As New ADODB.Recordset
---------------------------------------------
If rsRoute.State = 1 Then rsRoute.Close
Set rsRoute = New ADODB.Recordset
Set rsRoute.ActiveConnection = con
rsRoute.CursorLocation = adUseClient
rsRoute.CursorType = adOpenKeyset
rsRoute.LockType = adLockBatchOptimistic
strCmd = " select * from Table where CoumnVal =1 "
con.Errors.Clear
On Error Resume Next
rsRoute.Open strCmd
There are several types of CursorsType and two different CursorLocation varieties. On the Sybase database (ASE back in the day) the performance differs wildly depending on what you choose. Try both client-side and server-side cursors and see what happens.
If you just need to loop through the result once, select the adOpenForwardOnly cursor type. It usually results in the best performance.
EDIT: Based on the code you posted, try a) not locking anything (e.g LockType), b) using a adOpenForwardOnly cursor, a) the keep the cursor on the server (adUseServer)

How to get sets of Records in VB6?

Hey guys, just want to ask you a simple question that I know you're familiar with... I am using VB6, I just want to get sets of records from my database. What I mean is that I have UserID and with a part of code provided below, it only gets a single set of record. Like for instance, the value of UserID is A12, and so, all sets of records with the UserID of A12 must display in Textboxes respectively with the aid of datPayroll.Recordset.MoveNext.
With datPayroll
.RecordSource = "select * from tblpayroll where empid like '" & UserID & "'"
.Refresh
Me.txtRegularHours.Text = .Recordset.Fields!reghours
End With
-datPayroll : DataControl
-txtRegularHours : Textbox
-UserID : Variable
You probably want to look at MoveFirst, MoveNext, etc. and also EOF
Here is a link or two to get you started:
EOF, BOF
MoveFirst, MoveNext
You need to check that you have some data in your Recordset using EOF, then MoveFirst to move to the first record, and loop through using MoveNext.

Resources