I have a SQL query pulling back two columns and populating an ActiveX Combobox. The query in SQL returns a single row of data, however when I select the combobox in Excel the list is empty.
This is the part of the code that populates the combobox:
With rst
Set .ActiveConnection = Nothing 'Disconnect the recordset.
k = .Fields.Count
'Populate the array with the whole recordset.
vaData = .GetRows
End With
CB_Layer.List = Application.Transpose(vaData)
To test this I have added a watch to the rst and can see that I have one row of values. As soon as I pass over the vaData = .GetRows the watch value changes to:
: Value : <Either BOF or EOF is True, or the current record has been deleted. Requested operation requires a current record.>
Can anyone advise why this is happening?
Thanks in advance
Related
I am having a difficult time how to properly copy specific field data from previous records on my user form. I don't have a code sample to show but my request is very simplistic.
Currently, out of 12 fields, I have 6 that I often repeat data. I can click on and press Ctrl+' ("Insert the value from the same field in the previous record") and it performs the task I want. However, it adds a lot of time to the task. I simply want to write VBA code to perform that command to those specific fields.
I haven't been able to get SendKeys to work. DLast appears to provide random data at times. I feel like this should be a very simple request but for some reason I am not finding a functional solution for it.
Don't fiddle with arrays or queries - use the power of DAO:
Private Sub CopyButton_Click()
CopyRecord
End Sub
If a record is selected, copy this.
If a new record is selected, copy the last (previous) record.
Private Sub CopyRecord()
Dim Source As DAO.Recordset
Dim Insert As DAO.Recordset
Dim Field As DAO.Field
' Live recordset.
Set Insert = Me.RecordsetClone
' Source recordset.
Set Source = Insert.Clone
If Me.NewRecord Then
' Copy the last record.
Source.MoveLast
Else
' Copy the current record.
Source.Bookmark = Me.Bookmark
End If
Insert.AddNew
For Each Field In Source.Fields
With Field
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
Else
Select Case .Name
' List names of fields to copy.
Case "FirstField", "AnotherField", "YetAField" ' etc.
' Copy field content.
Insert.Fields(.Name).Value = Source.Fields(.Name).Value
End Select
End If
End With
Next
Insert.Update
Insert.Close
Source.Close
End Sub
This also, by the way, is an excellent example of the difference between the RecordsetClone and the Clone of a recordset - the first being "the records of the form", while the second is an independant copy.
This also means, that the form will update automatically and immediately.
Provided that it's a simple form to edit a simple table, and that the bound data field names match the control names, you may get away with
If Me.Recordset.AbsolutePosition > 0 Then
With Me.Recordset.Clone()
.AbsolutePosition = Me.Recordset.AbsolutePosition - 1
Dim control_name As Variant
For Each control_name In Array("field1", "field2", "field3", "field4", "field5", "field6")
Me.Controls(control_name).Value = .Fields(control_name).Value
Next
End With
End If
which you assign to a separate button on the same form.
You have a good idea post here already.
You could also say place a function in the before insert event. This event ONLY fires when you start typing into a NEW reocrd, and it becomes dirty.
So, maybe this:
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim rstPrevious As DAO.Recordset
Dim strSQL As String
strSQL = "SELECT TOP 1 * FROM tblPeople ORDER BY ID DESC"
Set rstPrevious = CurrentDb.OpenRecordset(strSQL)
' auto file out some previous values
If rstPrevious.RecordCount > 0 Then
Me.Firstname = rstPrevious!Firstname
Me.LastName = rstPrevious!LastName
End If
End Sub
And some good ideas in say having a "list" or "array" of controls/fields to setup, so you don't have to write a lot of code. (as suggested in the other post/answer here)
I am having a difficult time how to properly copy specific field data from previous records on my user form. I don't have a code sample to show but my request is very simplistic.
Currently, out of 12 fields, I have 6 that I often repeat data. I can click on and press Ctrl+' ("Insert the value from the same field in the previous record") and it performs the task I want. However, it adds a lot of time to the task. I simply want to write VBA code to perform that command to those specific fields.
I haven't been able to get SendKeys to work. DLast appears to provide random data at times. I feel like this should be a very simple request but for some reason I am not finding a functional solution for it.
Don't fiddle with arrays or queries - use the power of DAO:
Private Sub CopyButton_Click()
CopyRecord
End Sub
If a record is selected, copy this.
If a new record is selected, copy the last (previous) record.
Private Sub CopyRecord()
Dim Source As DAO.Recordset
Dim Insert As DAO.Recordset
Dim Field As DAO.Field
' Live recordset.
Set Insert = Me.RecordsetClone
' Source recordset.
Set Source = Insert.Clone
If Me.NewRecord Then
' Copy the last record.
Source.MoveLast
Else
' Copy the current record.
Source.Bookmark = Me.Bookmark
End If
Insert.AddNew
For Each Field In Source.Fields
With Field
If .Attributes And dbAutoIncrField Then
' Skip Autonumber or GUID field.
Else
Select Case .Name
' List names of fields to copy.
Case "FirstField", "AnotherField", "YetAField" ' etc.
' Copy field content.
Insert.Fields(.Name).Value = Source.Fields(.Name).Value
End Select
End If
End With
Next
Insert.Update
Insert.Close
Source.Close
End Sub
This also, by the way, is an excellent example of the difference between the RecordsetClone and the Clone of a recordset - the first being "the records of the form", while the second is an independant copy.
This also means, that the form will update automatically and immediately.
Provided that it's a simple form to edit a simple table, and that the bound data field names match the control names, you may get away with
If Me.Recordset.AbsolutePosition > 0 Then
With Me.Recordset.Clone()
.AbsolutePosition = Me.Recordset.AbsolutePosition - 1
Dim control_name As Variant
For Each control_name In Array("field1", "field2", "field3", "field4", "field5", "field6")
Me.Controls(control_name).Value = .Fields(control_name).Value
Next
End With
End If
which you assign to a separate button on the same form.
You have a good idea post here already.
You could also say place a function in the before insert event. This event ONLY fires when you start typing into a NEW reocrd, and it becomes dirty.
So, maybe this:
Private Sub Form_BeforeInsert(Cancel As Integer)
Dim rstPrevious As DAO.Recordset
Dim strSQL As String
strSQL = "SELECT TOP 1 * FROM tblPeople ORDER BY ID DESC"
Set rstPrevious = CurrentDb.OpenRecordset(strSQL)
' auto file out some previous values
If rstPrevious.RecordCount > 0 Then
Me.Firstname = rstPrevious!Firstname
Me.LastName = rstPrevious!LastName
End If
End Sub
And some good ideas in say having a "list" or "array" of controls/fields to setup, so you don't have to write a lot of code. (as suggested in the other post/answer here)
I am creating a DB in Access and using VBA to implement a feature to run several INSERT queries into multiple tables, based on values found in other 'template' tables.
At a certain point in the process, I am retrieving the results of a SELECT query and using the results of the query as parameters in an INSERT.
I have built and tested the query using the Access query builder so I know that the query functions as expected.
I am using the DAO library to interface with the DB and run my queries.
I have the function below which converts a recordset returned from the latter function to a collection of collections.
In the function below have run into a problem where the recordset I return apparently contains zero records. This causes it to throw a 'No Current Record' exception on the line 'records.MoveLast'.
What I should be seeing, which I know from the query, is a Recordset containing 2 records, with 5 fields each.
Private Function RecordsetToCollection(records As RecordSet) As Collection
Dim recordCollection As New Collection
Dim i As Integer
'Go to first record?
'Exception thrown here
records.MoveLast
records.MoveFirst
'Check if current record position before first record
If Not records.BOF Then
'While not after last record
While Not records.EOF
'Collection to hold field values
Dim fieldCollection As New Collection
'Loop through fields
For i = 0 To records.Fields.Count - 1
'Add to collection
fieldCollection.Add records.Fields(i).Value
Next i
'Add field collection to record collection
recordCollection.Add fieldCollection
Set fieldCollection = Nothing
'Go to next record
records.MoveNext
Wend
End If
'Return collection
Set RecordsetToCollection = recordCollection
End Function
The recordset being fed into this function is retrieved using the following function:
Private Function GetTemplateDeliverables(TemplateProjectActivityID As Integer) As Collection
'Get Template Deliverables recordset from tbl_TemplateDeliverables using given ProjectActivityID
'Open query
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.QueryDefs("qry_GetTemplateDeliverables")
'Add parameters
qdf.Parameters("Project Activity ID") = ProjectActivityID
'Get return recordset
Dim rst As RecordSet
Set rst = qdf.OpenRecordset()
Dim recordCollection As New Collection
Set recordCollection = RecordsetToCollection(rst)
'Get ProjectActivityID from recordset
Set GetTemplateDeliverables = recordCollection
'Clean up
qdf.Close
Set qdf = Nothing
Set rst = Nothing
End Function
Does anyone have any suggestions as to why this may be the case?
I can't see why this isn't working given that I already have functions to retrieve recordsets that are working fine, the only difference being that in those functions each record has only 1 field, whereas this has 5 fields, but I can't think why this would be a problem.
Any help would be much appreciated!
(P.S. any tips on how to improve my code would also be of help.)
First time asking here, so sorry if you find it annoying.
I've been trying to fill a ComboBox in an Excel Sheet with the result set of a DB procedure. So far, I've received the result set correctly, but when I try to specify the column I'd like to use to set the combo box values (3rd of the response), it keeps using the id's (1st column), even when I'm using the .BoundColumn command as follows:
cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "mySP"
Set rst = cmd.Execute()
With rst
i = .Fields.Count
vData = .GetRows
End With
With Sheet1
With .ComboBoxP
.Clear
.BoundColumn = 3
.List = Application.Transpose(vData)
.ListIndex = -1
End With
.ComboBoxP.Text = "-- Pick one --"
End With
Is there something wrong with the command order that makes the code to use always the same column? May it be an Excel version issue (I'm using MS Excel 2010 in spanish)?
You should be using the TextColumn property for setting which value gets shown to the user. The BoundColumn property sets which value your code gets when it reads the Value property of the control after the user has made a selection.
I have a field named "name" and I want to loop through that field and get each row value in a form such that it can be saved to a VBA variable. I'm having an issue with specifying the column & row and saving it to a VBA variable. Can anyone help me with this?
A data bound form has has a Recordset. It also has a RecordsetClone, which is a read-only copy of the Recordset.
Using VBA, you can loop through the rows of the RecordsetClone and read the value of any field in the current row. Most often we indicate which field we want to read by field name rather than the field's ordinal position, but you can do it either way.
Dim rs As DAO.Recordset
Set rs = Me.RecordsetClone
rs.MoveFirst
Do While Not rs.EOF
Debug.Print rs!id ' value of field named id '
Debug.Print rs(0) ' value of first field in recordset '
rs.MoveNext
Loop
Set rs = Nothing