I am trying to create a new result set each time I run the query... This way when I get to displaying the information, I will have different result sets for my different tables... Is it possible to change the name of a result set in a for loop?
Something like this would explain what I mean.. On the last line I do a For i = 0 to count -2... I am wondering if I could have the rsTemp(1,2,3,4,5) set to I so that if I do have 5 Queries... I would have rsTemp1,rsTemp2,rsTemp3,rsTemp4, and rsTemp5:
'1st Table Informations
strSQL = "SELECT DISTINCT custpart FROM dex_racklabels..rl_master where custpart like '%-%' and userid <> 'dakkota' and status <> 'S'"
Set rsTemp5 = conPaintDC.Execute(strSQL)
If Not rsTemp5.EOF Then
'If this returns something create an array of the returned rack serial numbers
Do While Not rsTemp5.EOF
strArrayPart = strArrayPart & "'" & rsTemp5("custpart") & "',"
rsTemp5.MoveNext
Loop
rsTemp5.MoveFirst
End If
'Split up the Part Numbers
ArraySplit = Split(strArrayPart,",")
'Count how many items you have
For each item In ArraySplit
count = count + 1
Next
'Run query for each
For i = 0 to count - 2
strSQL = "SELECT COUNT(serialnbr) FROM [dex_racklabels].[dbo].[rl_detail] where custpart = " & ArraySplit(i) & ""
Set rsTemp(1,2,3,4,5) = conPaintDC.Execute(strSQL)
If Not rsTemp(1,2,3,4,5).EOF Then
response.write(strSQL)
End If
Next
response.end()
"Numbered" variables (e.g. rsTemp1,rsTemp2,...) are a bad idea and should be avoided. In your case - a loop that deals with many recordsets sequentially - there is no need for extra/special/fancy variables at all, re-using a local variable is enough:
For Each query_spec
Set oRS = Obtain rs from query_spec
display oRS
close oRS
Next
If you need more than one recordset at the same time, use a collection (Array, Dictionary):
init collection c()
For Each query_spec
Set c(query_spec) = Obtain rs from query_spec
Next
For i = 1 To UBound(c) Step 2
WorkWith2Rs c(i-1), c(i)
Next
Related
I learned a couple of weeks ago how to update an Excel file via ADO. At that time the value was already given before changing it.
Now I want to add the procedure of reading the current value in the same cell and assign the value to a variable before changing it!
The current procedure looks as follows:
Public Sub ChangeNum()
Dim con As ADODB.Connection, rec As ADODB.Recordset
Dim sqlstr As String, datasource As String
Set con = New ADODB.Connection: Set rec = New ADODB.Recordset
datasource = "D:\DropBox\TraderShare\TraderNum.xlsx"
Dim sconnect As String
sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & datasource & ";" & _
"Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
con.Open sconnect
sqlstr = "UPDATE [Sheet1$] SET [Number] = """ & gsvDocNum & """ WHERE [ID] = """ & svNumRng & """"
rec.Open sqlstr, con ', adOpenUnspecified, adLockUnspecified 'adLockOptimistic , adOpenStatic, adLockReadOnly
con.Close
Set rec = Nothing: Set con = Nothing
End Sub
gsvDocNum is a global string variable declared in the beginning of the initial startup routine, hence after reading the current value into the variable, the UPDATE one will write gsvDocNum + 1 to the file.
svNumRng is one of the following named ranges, PNum, SNum, TNum or INum declared in the beginning of the main routine and determined which one to look for in an earlier stage (if it’s an Purchase, SalesOrder, TradeOrder or an Invoice).
I’m not so familiar with ADO and SQL strings and I can’t find the proper syntax for SELECT for reading the current cell value and assign it to a variable before changing it with the UPDATE.
Grateful for any help!
OK, the background as follows: We have an administrative program I’ve written myself in Excel vba for registering purchases, orders and invoices, etc. It works pretty well for our requirements but has one issue, keeping order numbers synced between the users! We are 3 users using the program locally, each one registering orders and such, but we share the serial number file via a shared DropBox folder. I have the idea that using ADO/SQL without opening the Excel file would be faster than open, change and save the file in Excel. The reason is of course to minimize the time updating the file thus the delay before syncing to the cloud Dropfox location and to the other users computers is minimized. It’s a simple 2 column Excel file, TraderNum.xlsx:
ID Number
PNum 16000
SNum 16000
TNum 16132
INum 16173
I learned a couple of weeks ago how to change one of the numbers from Excel without opening the file using ADO/SQL, (see above). But I discovered that a constant update of the Excel link to a closed file for having the current number available before changing it doesn’t work as expected. Accordingly I want to use ADO/SQL also to read/assign the specific current number to a variable in the Excel procedure, before changing it with the ADO/SQL procedure above.
So somewhere between the 2 commands, rec.Open sconnect and con.Close there should be a SQL-string similar to:
sqlread = "SELECT """ & DocNumOld & """ = [Number] FROM [Sheet1$] Where [ID] = """ & svNumRng & """"
where the DocNumOld variable is assigned the current number from the chosen ID variable svNumRng.
Then the DocNumNew variable is and assigned with the DocNumOld variable incremented with 1 followed by the
sqlUpdate sequence. It should look similar to the following:
Public Sub ChangeNum()
Dim con As ADODB.Connection, rec As ADODB.Recordset
Dim sqlRead as String, sqlUpdate As String, datasource As String, sconnect As String
Set con = New ADODB.Connection: Set rec = New ADODB.Recordset
datasource = "D:\DropBox\TraderShare\TraderNum.xlsx"
sconnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & datasource & ";" & _
"Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
con.Open sconnect
sqlRead = "SELECT """ & DocNumOld & """ = [Number] FROM [Sheet1$] Where [ID] = """ & svNumRng & """"
sqlUpdate = "UPDATE [Sheet1$] SET [Number] = """ & DocNumNew & """ WHERE [ID] = """ & svNumRng & """"
rec.Open ???????, con
????? sqlRead
DocNumNew = DocNumOld + 1
UNION
????? sqlUpdate
con.Close
Set rec = Nothing: Set con = Nothing
End Sub
Can you solve this, please?
Can anyone give me a solution to how to use ADO/SQL also to read/assign one specific current number to a variable in an Excel procedure, before changing it with the ADO/SQL procedure?
I am concerned I don't understand your question, because the resulting comments don't make sense to me.
To restate your problem: you need to know the value of some cell, and be able to feed it into your code.
You can already connect to a worksheet with SQL, you already know what SELECT statements are, and you probably already know how to run them. Humor me.
sqlRead = "SELECT * FROM [Sheet1$A12:F48]"
Set rec = con.Execute(sqlRead)
Now you have a recordset rec that contains the whole table. Say you wanted to put every value of the entire table in your immediate window:
Do While Not rec.EOF
For i = 0 To rec.Fields.Count - 1
Debug.Print rec.Fields(i).Name, rec.Fields(i).Value
Next
rec.MoveNext
Loop
Don't forget to close it, and I suggest using a second variable name anyway as the name of the recordset for the update statement.
rec.Close
Say you knew the cell would always be in the 3rd row, 8th column of the table you are selecting from, you might:
For j = 0 to myRowNum-1 'you have set myRowNum equal to 3 earlier'
rec.MoveNext
Next
myOldCellValue = rec.Fields(myColNum-1).value 'you have set myColNum to 8 earlier'
rec.Close
Now, say you don't know exactly which row you will find myOldCellValue, but you know it will be found in the 4th column of the row that has the unique [ID] 1234, you might:
sqlRead = "SELECT * FROM [Sheet1$A12:F48] Where [ID] = """ & myIDNum & """" 'you have set myIDNum to 1234 earlier
Set rec = con.Execute(sqlRead)
myOldCellValue = rec.Fields(myColNum-1).value 'you have set myColNum to 4 earlier'
rec.Close
Say you wanted to UPDATE every row that had that value (I don't read that you, but for completeness), you might:
sqlUpdate="UPDATE [Sheet1$] SET [Number] = """ & DocNumNew & """ WHERE [DocNum] = """ & myOldCellValue & """"
I have created below piece of code in order to amend some data in an Access table:
Dim Ways As DAO.Recordset
Dim Keys As DAO.Recordset
Dim Recordcount As Double
Dim Records As Double
Dim ID_Old As String
Dim ID_New As String
Dim STArray() As String
Dim SaveTime As String
Set Ways = CurrentDb.OpenRecordset("Ways_Sorted")
Recordcount = 1
Records = 3724755
Ways.MoveFirst
Dim word As Variant
While Not Ways.EOF
DoCmd.SetWarnings (False)
DoCmd.OpenQuery "KeyFind:DEL"
DoCmd.SetWarnings (True)
Set Keys = CurrentDb.OpenRecordset("KeyFind")
STArray = Split(Ways!Veld4, ";")
For Each word In STArray
If Len(word) > 0 Then
Keys.AddNew
Keys!IDOld = CDbl(word)
Keys!IDNew = DLookup("[New ID]", "ID Keys", "[Old ID]=" & CDbl(word))
Keys.Update
End If
Next
Keys.MoveFirst
While Not Keys.EOF
ID_Old = " " + Trim(Str$(Keys!IDOld))
ID_New = " " + Trim(Str$(Keys!IDNew))
Ways.Edit
Ways!Veld4 = Replace(Ways!Veld4, ID_Old, ID_New)
Keys.MoveNext
Wend
Keys.Close
Me.Tekst1 = Recordcount
Me.Tekst3 = Records - Recordcount
Me.Tekst5 = FileLen(Application.CurrentProject.Path & "\Map_Convert_2.mdb")
If FileLen(Application.CurrentProject.Path & "\Map_Convert_2.mdb") > 1977142784 Then
' Exit Sub
End If
DoEvents
Ways!Done = True
Ways.Update
Ways.MoveNext
Recordcount = Recordcount + 1
'CommandBars("Menu Bar").Controls("Tools").Controls("Database utilities").Controls("Compact and repair database...").accDoDefaultAction
'Stop
Wend
DoCmd.SetWarnings (False)
DoCmd.OpenQuery "Ways_Amend ID"
DoCmd.SetWarnings (True)
MsgBox "New Map created"
Actually what the code is doing is replacing the data in field "Veld4" in table "Ways_Sorted". This field holds a string with ID's, which is splitted with STArray = Split(Ways!Veld4, ";") into an array.
This array is stored in a table called "KeysFound".
Another table in my database is containing the old ID and the new ID.
As said the rest of the code will replace the old id in "Veld4"with the new ID.
It is looping through 3.7 million records this way.
My problem is that after 250 loops or so my database has grown with 1mB, meaning that my database will be above the 2gB way before the code has finished.
I can not explain why the growth is happening and how I can stop this or at leas reduce the growth
Your code has lots of potential for optimization.
Main issue: you are constantly writing into and deleting from the Keys table. I guess this is also the cause of the growth issue.
This table is unnecessary. Just do the replacement right after reading each key. Build the new Veld4 as string NewVeld, only write it into the table once you are finished for the current Ways row.
STArray = Split(Ways!Veld4, ";")
NewVeld = ""
For Each word In STArray
If Len(word) > 0 Then
NewKey = DLookup("[New ID]", "ID Keys", "[Old ID]=" & CDbl(word))
' you will have to adapt this to your exact "veld" structure
' If there is a specific reason, you can also continue to use Replace(),
' but I don't think it's necessary.
NewVeld = NewVeld & ";" & NewKey
End If
Next
' remove leading ";"
NewVeld = Mid(NewVeld, 2)
Ways.Edit
Ways!Veld4 = NewVeld
Ways!Done = True
Ways.Update
Ways.MoveNext
Further optimization: DLookup is a rather expensive operation for your row count.
Consider loading the whole ID Keys table into a Dictionary object at the beginning, then reading the new IDs from there.
I have an Access database with about 500,000 records. There is a specific column which has the transaction reference.
This is of the form:
Transaction_Ref
CDY1053N1
CDY1053N2
CDY1053N3
JFD215D1
JFD215D2
Where CDY1053N and JFD215D are customer references, and the 1,2,3, etc which follows is the transaction number.
What I am looking for is a loop which will update a column called "Group". This will go to row 1, and loop through the database to find transaction references similar to CDY1053N and assign a group ID, for example:
Transaction_Ref Group_ID
CDY1053N1 1
CDY1053N2 1
CDY1053N3 1
JFD215D1 2
JFD215D2 2
Any ideas please?
Thanks for the help.
This might not be the best or most elegant way to do this (particularly with the number of records you have), but this worked on my small set of test records.
I've assumed Transaction_Ref and Group_ID are in the same table and I've called that table tblTransactions.
I've also assumed that you might want to run this on new data so have nulled the Group_ID before looping through and resetting the values. This could mean that a different value for Group_ID gets assigned for a group of records (for example, were your records change order between subsequent runs of this sub).
If that's a problem you'll need to tweak this a bit.
Public Sub AssignGroupID()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim sql As String
Dim i As Integer
Set db = CurrentDb
' Clear the Group_ID column (in case you want to run this more than once)
sql = "UPDATE tblTransactions Set Group_ID = Null"
db.Execute sql
' Open your table with the Transaction_Ref and Group_ID fields
Set rs = db.OpenRecordset("tblTransactions")
' Zero the counter
i = 0
' Start the loop (set it to end when it gets to the last record)
Do While Not rs.EOF
' Only update Group_IDs that haven't got a value yet
If IsNull(rs!Group_ID) Then
' Push the counter on
i = i + 1
' Update all Group_IDs with current counter number that
' match the customer reference of the current record
sql = "UPDATE tbltransactions Set Group_ID = " & i & " WHERE " _
& "Left(tblTransactions.Transaction_Ref, Len(tblTransactions.Transaction_Ref) -1) = '" _
& Left(rs!Transaction_Ref, Len(rs!Transaction_Ref) - 1) & "'"
db.Execute sql
End If
' Move to the next record
rs.MoveNext
Loop
'clean up
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
In classic ASP I need to extract data out of a MSSQL database, passing the results to a two dimensional array (rows, columns) and display the data in various formats.
For each such format I need to build functions to display data. So, in order to be as modular as possible I need to separate (i) extraction and passing data to the array from (ii) displaying the results.
My code does currently the extraction of data using a class, but also displays (within the same class) the data in a primitive way (just to test that the data is extracted and correct).
How can I pass such array to a function? You can imagine how flexible would be to have an array as data input into a function and then manipulate it (creating many functions) when trying to display it in a table (example: function 1 will be based on template no. 1 of a table that is red with background black and no borderline, function 2 is built on the template 2, the table is green, with borderline and yellow background, etc etc).
Here is my code and at the end of the main function (within the class) you will see a portion that displays results, i.e. the one that I need to do it separately from / outside the class (i.e. in the functions to be created).
<!--#include file ="../functions/fctGetnrofrecords.asp"-->
<%
Dim db : Set db = New GetRowsFromAdatabase
db.strTable="Customers"
strDisplay=db.FindOutRecordsAndPassThemToAnArray()
Response.Write strDisplay
Class GetRowsFromAdatabase
Public strTable
Public numberOfRecords
Public numberOfFields
Public Function FindOutRecordsAndPassThemToAnArray()
Set conn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
'Find out connecting credentials
strSERVERspecific=Coli(0)
strDATABASENAMEspecific=Coli(1)
strUIDspecific=Coli(2)
strPWDspecific=Coli(3)
conn.Open "Provider=SQLOLEDB;server=" & strSERVERspecific & ";database=" & strDATABASENAMEspecific & ";uid=" & strUIDspecific & ";pwd=" & strPWDspecific & ";"
rs.Open strTable, conn
if rs.EOF and rs.BOF then
strError = "There is no record in the table " & strTable
else
'Assign the Number Of Fields to the variable “counter”
counter = rs.fields.count
numberOfFields=counter
Dim matrix(25, 10) ' these exceed by far the values of numberOfRecords and numberOfFields
for j=0 to counter-1
matrix(0,j)= rs.Fields(j).Name ' The first dimension of the array, when is zero,
' is populated with the names of fields
next
rs.movefirst
i=1
do until rs.EOF
for j=0 to counter-1
matrix(i,j)=rs(j)
next
i=i+1
rs.movenext
loop
end if
' Now, I need this class not to include the displaying section that follows
' (i.e. see the portion until the end of this function), although this section works fine
numberOfRecords=fctGetNumberOfRowsOfaTable(strTable)
'see the include directive at the beginning of this code (there is a function there that does this)
'====begin section that displays the arrays values
for m = 0 to numberOfRecords
for n=0 to counter-1
strDisplay = strDisplay & m & "," & n & "=" & matrix(m,n) & "<br>"
next
next
'====end section that displays the array values
FindOutRecordsAndPassThemToAnArray = strDisplay
End Function
Public Function Coli(x)
'This function read a line of a txt file located on the server side (hidden from public / httpdocs)
' where x = the relevant line out of the following
' 1 means the 1st line = name / IP server
' 2 means the 2nd line = database name
' 3 means the 3rd line = user name available in the database
' 4 means the 4th line = user’s password
if x<0 or x> 3 then
Coli="Erorr"
Exit Function
else
serv=Server.MapPath("../../../")
path=serv & "\somehiddenfolder\"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile(path & "configuration.txt")
J=0
Dim Datele(3)
Do Until objTextFile.AtEndOfStream
strNextLine = objTextFile.Readline
if x=J then
Coli=strNextLine
exit function
else
J=J+1
end if
Loop
end if
End Function
End Class
%>
Any hints will be highly appreciated.
Use .GetRows to get an array of a table/resultset. To pass such an array to a function (why function? what should be its return value?) you write its name in the argument list of the function call.
Update wrt comment:
Sample of calling a function that expects an array:
>> Function sum(a)
>> sum = Join(a, "+")
>> End Function
>> a = Split("1 2 3")
>> WScript.Echo sum(a)
>>
1+2+3
Instead of Split() - which returns a one dimensional array - you'd use .GetRows() on a valid recordset (and keep in mind that .GetRows() returns a two dimensional array).
I am getting a huge amount of data from my database which I before iterated through in a recordset like this:
sql = "select * from table"
set rs = conn.execute(sql)
if not rs.eof then
do until rs.eof
id = rs("id")
fullname = rs("fullname")
response.write("<a href='/" & id & "'>Hi " & fullname & ".<br />")
rs.movenext
loop
Now I am using a static recordset using GetRows() like this:
sql = "select * from table"
set rssql = conn.execute(sql)
if not rssql.eof then
rs = rssql.getrows()
end if
rssql.close
if isarray(rs) then
for counter = lbound(rs) to ubound(rs)
id = rs(0, counter)
fullname = rs(1, counter)
response.write("<a href='/" & id & "'>Hi " & fullname & ".<br />")
next
end if
Is it really not possible to do something like rs("id", counter) instead of using static numbers? I have a dynamic amount of coloumns (created by the system) in my table and it is very dynamic which of them I need. The number of coloumns I need in each rows are specificed by another coloumn in the row.
GetRows returns a vanilla array & as such is only addressable by a numeric index.
If you feel you need to dispose of the connection as soon as possible for some reason, you can fully populate the recordset and disconnect is as describe here.
(You can always use the initial recordset to populate another array or collection with the column names via the .Fields collection)
rs.Fields(counter).Name will give you access to column names. Unfortunately getrows() does not create an associative array, so you cannot look up data by column name.