MS access select specific data cell - sql

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

Related

Runtime error 3164 for Access when copying [duplicate]

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)

Editing a record immediately after creating it

For my paste function, in certain cases, I need to be able to create a record and immediately edit it afterwards. This is because I need to know the value that gets generated for the AutoNumber field.
The error I get is "Update or CancelUpdate without AddNew or Edit." I marked where this error pops up in my code sample.
I pasted my entire paste function in case that it might help. Though the code that I am unsure of how to properly execute is in the bottom 4th (everything below the ***).
If you want to know exactly what I am trying to do feel free to read the rest of the post though it should be sufficient without.
Essentially what I am trying to do is for each record in my clipboard, I want to make a duplicate of it - copying values of all the fields. There are exceptions however. The ones of interest are the AutoNumber field, "ESDNodeID", and "ParentID" which is the ESDNodeID of the record that the record inherits from.
The clipboard (which contains the ESDNodeID and the ParentID) of the nodes that already exist which are being copied are sorted so that if a child record has a parent record, its parent is the next one in the list. So my idea is that I can use the AutoNumber value that gets generated for the record's id to find out what it will be for its parent id (which should just be its id + 1 since it is next in the for loop).
Public Function Paste(nodeID As Long)
Dim currScenarioID As Long
Dim i As Long
Dim saveParentIDs As Collection
Set saveParentIDs = New Collection
currScenarioID = Forms("Main")!Scenarios!ScenarioID
Dim rstSource As DAO.Recordset
Dim rstInsert As DAO.Recordset
Dim fld As DAO.Field
'We want to insert records into the ESDNodes table
Set rstInsert = CurrentDb.OpenRecordset("ESDNodes")
'We want to insert a record for each element in the clipboard
For i = 0 To UBound(clipboard)
'rstSource represents the record that we want to copy. Should only be 1 as ESDNodeID is unique.
Set rstSource = CurrentDb.OpenRecordset("SELECT * FROM ESDNodes WHERE ESDNodeID = " & clipboard(i)(0))
rstSource.MoveFirst
With rstInsert
'create a new record
.AddNew
'Want to copy all the fields
For Each fld In rstSource.Fields
With fld
If .Name = "ESDNodeID" Then
'Skip Autonumber field
'If the field is the ParentID
ElseIf .Name = "ParentID" Then
'If the clipboard has a NULL value that means the node selected is the Parent
If IsNull(clipboard(i)(1)) Then
rstInsert.Fields(.Name).value = nodeID
'If the parent ID has already been created for another node, we want to grab that ID
ElseIf Contains(saveParentIDs, CStr(clipboard(i)(1))) Then
rstInsert.Fields(.Name).value = saveParentIDs(CStr(clipboard(i)(1)))
'If neither of these conditions pass, the parentID is handled after the for loop
End If
'We want the active scenario id
ElseIf .Name = "ScenarioID" Then
rstInsert.Fields(.Name).value = currScenarioID
'Copy all other fields direcly from record
Else
rstInsert.Fields(.Name).value = .value
End If
End With
Next
'If the parent ID was not set above, that means we have not yet created the record corresponding to its parentID
'But because of how our clipboard is sorted, it will be the next one in the loop. Meaning that we can create this new record
'with an empty parentID, and then predict the id of its parent by simply adding 1 to its id
'*****************
.Update
.MoveLast
If Not IsNull(clipboard(i)(1)) Then
If Not Contains(saveParentIDs, CStr(clipboard(i)(1))) Then
!parentID = !ESDNodeID + 1 'ERROR HERE
saveParentIDs.Add !parentID, CStr(clipboard(i)(1))
.Update
End If
End If
.Close
End With
Next i
loadESDTreeView
End Function
You should use method .Edit before changing existing recordset fields.
Also don't close rstInsert inside For, it will fail on next row.
Few more things.
May be I didn't catch the whole idea, but if you moving to last row before editing it in order to just read ESDNodeID, generated after .AddNew, you don't need to use .Update with .MoveLast, you can read the new Id right after .AddNew, it is available.
Predicting of autonumber field value is bad idea, especially in multiuser environment.
Database integrity is very important, so ParentID should have foreign key constrain on ESDNodeID, in this case database won't allow you to insert not existing yet ESDNodeID. Try to review the logic of this procedure.

VBA Combobox not populating recordset

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

Access - Change fields in table automatically, if a field changes

Lets say I got a table with an id, pre- and lastname. I made them work as comboboxes in the table. Now if I change 1 field (lets say the id) with the combobox I want that all the other stuff is changed too (the pre and lastname). How to achieve that (with a macro or vba, or is it easier)?
I solved it. I made a sub formular. Then i managed to dropdown the fields I wanted to. Copying the same table for finding the names ids...
And then i created an event for after update:
Private Sub PartnerIdServiceWorker_AfterUpdate()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("SELECT * FROM HTB WHERE PartnerIdServiceWorker = " & PartnerIdServiceWorker)
Do While Not rst.EOF
Me.AnredeMitarbeiter = rst!AnredeMitarbeiter
Me.VornameMitarbeiter = rst!VornameMitarbeiter
Me.NachnameMitarbeiter = rst!NachnameMitarbeiter
Exit Do
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
Now I'm able to change the fields in the table and the other values do also change.

How to read recordset as string in VBA

I have some code to read records from a database. when i read , the recordset variable modifies the table value to its own format.
For Eg:
In Database
Time value is 12345 (Not date & time) but when record set reads it, it
comes as For Eg: 23-06-2012
10:15:23
I just found that the recordset itself stores values in its own format after doing.
Set rs = CmdSqlData.Execute()
So is there any way to define a recordset as String?
Here is the code.
Dim rs As ADODB.RecordSet
Set rs = CmdSqlData.Execute()
Do While (rs.EOF = FALSE And rs.BOF = FALSE)
p = rs.GetRows(1)
cell(1,1) = p(0,0)
Loop
Can anyone please let me know how to read the data as String (as it is in database) so that no change in format will occur.
Note: I can not convert Excel cell format due to other requirements but I want to read everthing as String From Table
If you write
CStr(p(0,0))
To a cell, Excel will convert to the appropriate type for the content, so if p(0,0) is a number, the cell will be numeric.
However, if you write
ActiveSheet.Cells(1, 1) = "'" & p(0, 0)
Cell A1 will contain '2 to view, but can be manipulated as a string. This is left over from the early days of Excel, where to enter a string you had to prefix it with a single quote.
A1
2
=A1=2 FALSE
=A1="2" TRUE