Extract and display data from access table using VBA - sql

I have a function to extract and then display a recordset in a listbox.
I only get one field in my listbox.
Is there a way I can display the whole column "Caption" (several fields) in the listbox?
Function GetCaption() As String
Dim db As Database
Dim rst As DAO.Recordset
Dim SQL As String
Dim LCaption As String
Set db = CurrentDb()
SQL = "SELECT Caption FROM tblMainMenu"
Set rst = db.OpenRecordset(SQL)
If rst.EOF = False Then
LCaption = rst("Caption")
Else
LCaption = "Not found"
End If
rst.Close
Set rst = Nothing
GetCaption = LCaption
End Function
Private Sub btnGetCaption1_Click()
LstBx.RowSourceType = "Value List"
LstBx.RowSource = GetCaption
End Sub
Private Sub Form_Load()
LstBx.RowSource = ""
btnGetCaption1.Caption = DLookup("ReportID", "tblMainMenu", "ReportID = 1")
End Sub

I'm not sure how well I understand your goal. But if you want the list box to contain tblMainMenu.Caption values, one per list box row, you can use the query as its Record Source.
With the form open in Design View, open the list box's property sheet, and select the Data tab. Then choose "Table/Query" for Row Source Type. Add this SQL for the Row Source property.
SELECT [Caption] FROM tblMainMenu
Then select the Format tab, and enter 1 for the Column Count property.
Finally switch to Form View and tell us whether that gives you what you want, or how it differs from what you want.

Related

populating multiple fields in subform using combobox and AfterUpdate Event Prodcedure

I am creating a set of Access database form for entering vegetation data into a linked SQL Server data base. For one protocol, I have created a form 'frmLPI' for entering data from a vegetation monitoring method called Line-Point-Intercept. It is a form with a subform within it called 'frmLPIDetail' where individual counts of plant species get recorded. The main form has three unbound controls: [TransectOID], [DataRec], and [DataObs]. TransectOID is a unique id for each time we ran protocol. For each TransectOID, there are 30 locations where we sampled vegetation these have a hidden unique id in the subform called LPI_OID. The subform is linked to the main form by TransectOID. I want my users to be able to click the unbound [DataRec] and [DataObs] comboboxes in the main form, and have the corresponding fields in the subform autopopulate for all 30 records. I have figure out how to accomplish this for record in the subform but can't figure out how to do it for 30 records for each value of TransectOID in the Main form. Below is a screenshot of my form to help you visualize what I am after:
And here is the code I have come up with to get one record to autopopulate
Private Sub Form_Load()
Me.TransectOID = Me.OpenArgs
End Sub
Private Sub Form_Deactivate()
DoCmd.RunCommand acCmdSaveRecord
End Sub
Private Sub DataObs_AfterUpdate()
Me!frmLPIDetail.Form!Data_observer = Me!DataObs
Me.Dirty = False
End Sub
Private Sub DataRec_AfterUpdate()
Me!frmLPIDetail.Form!Data_recorder = Me!DataRec
Me.Dirty = False
End Sub
Any suggestions would be much appreciated
Since inserting multiple records at a time is desirable your question has been asked before but I couldn't find an answer that was particularly helpful so I will provide a more general answer than you asked for.
Access doesn't provide default forms for inserting multiple records. You have to code that yourself but the process is always pretty much the same.
figure out a normalized table structure for your data
figure what data you need to collect from the user for the multiple insert
add a button to the form and put the vba for the multiple insert in the click event
so here is 1 normalized table structure that might fit your data:
Since I don't know where TransectionOID is coming from we let Access provide TransectionID as the primary key and assume TransectionOID is entered on another form. All the other information of interest is in the TransectionDetails table and there is no need to write a query to gather all the variables we will need into our forms record source to finish step 2. To get a jumpstart I selected the TransactionDetails table and used the create form wizard to make a tabular style form.
To finish step 2 we put controls in the header to collect the information from the user we will need and the start editing the form for user friendliness. For instance I delete the checkbox for TransectionDetailID in the details section and replace every other control with comboboxes. I normally replace the circled record selectors with comboboxes as well but here that may be confusing so I leave the record selectors to provide some search functionality. The final form looks like:
Finally, for step 3 we add the vba for the click event
Private Sub cmdInsert_Click()
Dim db As Database
Dim rs As Recordset 'using recordset because lower error rate than using sql strings
Set db = CurrentDb
Set rs = db.OpenRecordset("TransectionDetails")
Dim L As Integer
Dim S As Integer
If Not Me.lstLocations.ListCount = 0 Then 'if no locations are selected no records can be inserted
For L = 0 To Me.lstLocations.ListCount 'simple multiselect listbox version matters for the vba code
If Me.lstLocations.Selected(L) = True Then
For S = 0 To Me.lstSpecies.ListCount
If Me.lstSpecies.Selected(S) = True Then
rs.AddNew
rs!TransectionID = Me.cmbTransectionID
rs!Data_observer = Me.cmbData_observer
rs!Data_recorder = Me.cmbData_recorder
rs!TransectLocation = Me.lstLocations.Column(0, L) 'column gives you access to values in the listbox
rs!SpeciesID = Me.lstSpecies.Column(0, S)
If Not IsNull(Me.chkDead) Then 'chkDead is a triple value checkbox, this both avoids setting Dead to null and shows how to handle when the user doesn't set all controls
rs!Dead = Me.chkDead
End If 'chkdead
rs.Update
End If 'lstspecies selected
Next S
End If
Next L
End If
Me.Detail.Visible = True 'quick and dirty bit of style (detail starts invisible)
Me.Filter = "TransectionID = " & Me.cmbTransectionID 'more quick and dirty style filter to focus on inserted records
Me.FilterOn = True
'clean up
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub
Private Sub cmdSelectAllLocations_Click()
Dim i As Integer
For i = 0 To Me.lstLocations.ListCount
Me.lstLocations.Selected(i) = True
Next
End Sub
Private Sub cmdSelectAllSpecies_Click()
Dim i As Integer
For i = 0 To Me.lstSpecies.ListCount
Me.lstSpecies.Selected(i) = True
Next
End Sub
Private Sub cmdSelectNoLocations_Click()
Dim i As Integer
For i = 0 To Me.lstLocations.ListCount
Me.lstLocations.Selected(i) = False
Next
End Sub
Private Sub cmdSelectNoSpecies_Click()
Dim i As Integer
For i = 0 To Me.lstSpecies.ListCount
Me.lstSpecies.Selected(i) = False
Next
End Sub
While Mazoula's answer is far more elegant, I discovered a quick and dirty way to accomplish what I was after using a While loop. Below is my code:
Private Sub Form_Load()
Me.TransectOID = Me.OpenArgs
End Sub
Private Sub Form_Deactivate()
DoCmd.RunCommand acCmdSaveRecord
End Sub
Private Sub DataObs_AfterUpdate()
Dim rs As DAO.Recordset
Set rs = Me!frmLPIDetail.Form.RecordsetClone
rs.MoveLast
rs.MoveFirst
While Not rs.EOF
rs.Edit
rs!Data_observer.Value = Me.DataObs.Value
rs.Update
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
Me.Dirty = False
End Sub
Private Sub DataRec_AfterUpdate()
Dim rs As DAO.Recordset
Set rs = Me!frmLPIDetail.Form.RecordsetClone
rs.MoveLast
rs.MoveFirst
While Not rs.EOF
rs.Edit
rs!Data_recorder.Value = Me.DataRec.Value
rs.Update
rs.MoveNext
Wend
rs.Close
Set rs = Nothing
Me.Dirty = False
End Sub

Skip empty fields when adding a new record using vba

I have a form that users open to add new fees and services for clients. There are 10 fields for fees and I have it setup to auto-populate the fee verbiage if the user un-checks a "standard hourly rate" check box.
If they un-click Std-Hourly, then the field [Fee001] will go from being greyed out and blank, to display "Services # 1 through # 3...." and the user can edit the text if they need it to show "Services # 1 through #7" (depending on how many services the client has)
When the user clicks the Save button, I have the data then saved to TblFee_ByClient table. The table has a record for each service ([ClientID] and [Service] are the only 2 fields in this table) but the form itself has 10 fields ([Fee001], [Fee002], Fee003] and so on) that the user can edit/generate.
All works except my code also adds records for the fields that the user clears/deletes so that I have a record with [ClientID] and no service listed. How do I add code to skip fields that are empty? Here is the vba so far and I am getting an error "Argument not optional" on the "Move.Next":
Private Sub Toggle154_Click()
Dim TblFee_ByClient As DAO.Recordset
Set TblFee_ByClient = CurrentDb.OpenRecordset("SELECT * FROM [TblFee_ByClient]")
TblFee_ByClient.AddNew
TblFee_ByClient![ClientID] = Me.ClientID.Value
If Me.Fee001.Value Is Not Null Then
TblFee_ByClient![Fee] = Me.Fee001.Value
Else Move.Next
End If
TblFee_ByClient![ClientID] = Me.ClientID.Value
TblFee_ByClient![Fee] = Me.Fee002.Value
TblFee_ByClient.Update
TblFee_ByClient.Close
Set TblFee_ByClient = Nothing
End Sub
Correct syntax is TblFee_ByClient.MoveNext but don't see it's needed here.
Use IsNull() in VBA. Is Null is for queries. Or better, handle possibility of Null or empty string.
Don't open recordset with existing records.
Need a conditional statement for each of the 10 controls. This can be accomplished in a loop.
Private Sub Toggle154_Click()
Dim TblFee_ByClient As DAO.Recordset
Dim x As Integer, strFee As String
Set TblFee_ByClient = CurrentDb.OpenRecordset("SELECT * FROM [TblFee_ByClient] WHERE 1=0")
With TblFee_ByClient
For x = 1 To 10
strFee = "Fee" & Format(x, "000")
If Nz(Me(strFee), "") <> "" Then
.AddNew
!ClientID = Me.ClientID
!Fee = Me(strFee)
.Update
End If
Next
.Close
End With
Set TblFee_ByClient = Nothing
End Sub

Is it possible to use a Pivot Table in a userform?

Is it possible to insert a pivot table into a userform in VBA? I saw this other question about it, but I'm able to find the Microsoft Office PivotTable control in the right-click menu. I did find the Tree View, but that isn't quite the same thing I don't think.
UPDATE
I'm creating an Inventory workbook for use in my office. I'll allow others to use it to see what we have and to request items that we have in inventory. I'm going to use the Userform for this. I have a dashboard for myself in the workbook that has several pivot tables already. There are 2 that I'd like to use in the Userform.
The regular users won't have access to edit the workbook, or even to change which sheet is showing, they only need access to view the 2 pivots that I want to add to this Userform.
So, the end result is going to be that the end user will have a pivot table that will allow them to see what we have in inventory and request it or send an email that will create a PO to order it.
I've been using Excel for a very long time and I've never heard of anyone need this combination (UserForm+PT), but anyway, I did a quick Google search and came up with this.
Option Explicit
Dim cnnConnection As Object
Private Sub Form_Load()
Dim strProvider As String
Dim view As PivotView
Dim fsets As PivotFieldSets
Dim c As Object
Dim newtotal As PivotTotal
strProvider = "Microsoft.Jet.OLEDB.4.0"
' Create an ADO object
Set cnnConnection = CreateObject("ADODB.Connection")
' Set the provider and open the connection to the database
cnnConnection.Provider = strProvider
cnnConnection.Open "C:\pivottest.mdb"
' Set the pivot table's connection string to the cnnConnection's connection string
PivotTable1.ConnectionString = cnnConnection.ConnectionString
' SQL statement to get everything from table1
PivotTable1.CommandText = "Select * from table1"
' Get variables from the pivot table
Set view = PivotTable1.ActiveView
Set fsets = PivotTable1.ActiveView.FieldSets
Set c = PivotTable1.Constants
' Add Category to the Row axis and Item to the Column axis
view.RowAxis.InsertFieldSet fsets("Category")
view.ColumnAxis.InsertFieldSet fsets("Item")
' Add a new total - Sum of Price
Set newtotal = view.AddTotal("Sum of Price", view.FieldSets("Price").Fields(0), c.plFunctionSum)
view.DataAxis.InsertTotal newtotal
view.DataAxis.InsertFieldSet view.FieldSets("Price")
' Set some visual properties
PivotTable1.DisplayExpandIndicator = False
PivotTable1.DisplayFieldList = False
PivotTable1.AllowDetails = False
End Sub
Private Sub Form_Terminate()
' Remove reference to the ADO object
Set cnnConnection = Nothing
End Sub
Private Sub PivotTable1_DblClick()
Dim sel As Object
Dim pivotagg As PivotAggregate
Dim sTotal As String
Dim sColName As String
Dim sRowName As String
Dim sMsg As String
' Get the selection object you double-clicked on
Set sel = PivotTable1.Selection
' If it is a aggregate, you can find information about it
If TypeName(sel) = "PivotAggregates" Then
' Select the first item
Set pivotagg = sel.Item(0)
' Display the value
MsgBox "The cell you double-clicked has a value of '" & pivotagg.Value & "'.", vbInformation, "Value of Cell"
' Get variables from the cell
sTotal = pivotagg.Total.Caption
sColName = pivotagg.Cell.ColumnMember.Caption
sRowName = pivotagg.Cell.RowMember.Caption
' Display the row and column name
sMsg = "The value is " & sTotal & " by " & sRowName & " by " & sColName
MsgBox sMsg, vbInformation, "Value Info"
End If
End Sub
See if you can adapt that concept to your specific setup.
https://support.microsoft.com/en-us/help/235542/how-to-use-the-pivottable-office-web-component-with-vb

Query error on a recordset.update vba line

I am trying to print multiple labels for multiple records. The number of labels is consistent for any one run of the label report and all labels for the same record need to be together on the printed sheet. Parameters are entered on TakeNoticeForm and once a button is clicked a recordset, rsQuery, is created with TakeNoticeLabelQuery. Another recordset is created, rsTable, based on a table, TemporaryTNLabels. This table is a copy of my main table, Certificates, without data. I'm using nested For loops to parse through the query results and add "x" copies of said record into the temp table, which will then be used to print the labels. Once the labels are printed the data will be cleared from the temp table for use again later.
Everything I have so far appears to work until I actually start adding data to my temp table. I get Error 3991 - "The query failed to execute because the identifier '[Certificates].[TownshipID]' could not be found" and it points to .Update. [TownshipID] is a lookup field in the Certificates table that was the original for TemporaryTNLabels. I tried to keep the copy intact for possible reuse with other reports but I don't need that field for this report so deleted the lookup field from the temp table to hopefully solve the problem. TakeNoticeLabelQuery is actually a copy of another query, TakeNoticeQuery, that did reference Township information. Again, I was hoping to reuse objects but made a copy and only kept what I needed, which has no reference to TownshipID.
After stripping everything unnecessary away, I can't figure out why it's still trying to find [TownshipID]. I'm still trying to wrap my head around recordsets so wondering if the problem is actually elsewhere, buty I'm confused as to how this error is even remotely related to my code. Any help is appreciated. The SQL for the query and code for generating label data are below.
SELECT Certificates.DatabaseID, Certificates.CertCounty, Certificates.TaxYear, Certificates.ParcelNumber, Certificates.MailToFirstName, Certificates.MailToLastName, Certificates.MailToAlso, Certificates.MailToCity, Certificates.MailToState, Certificates.MailToZip
FROM Counties INNER JOIN Certificates ON Counties.ID = Certificates.CertCounty
WHERE (((Certificates.DatabaseID) Between ([Forms]![TakeNoticeForm]![FirstDBTextbox]) And ([Forms]![TakeNoticeForm]![LastDBTextbox])) AND ((Certificates.CertCounty) Like [Forms]![TakeNoticeForm]![CountyCombobox] & '*') AND ((Certificates.TaxYear) Like [Forms]![TakeNoticeForm]![TaxYearTextbox] & '*')) OR (((Certificates.CertCounty) Like [Forms]![TakeNoticeForm]![CountyCombobox] & '*') AND ((Certificates.TaxYear) Like [Forms]![TakeNoticeForm]![TaxYearTextbox] & '*') AND ((IsNull([Forms]![TakeNoticeForm]![FirstDBTextbox]))<>False) AND ((IsNull([Forms]![TakeNoticeForm]![LastDBTextbox]))<>False));
Option Compare Database
Option Explicit
Private Sub TNLabelPreviewButton_Click()
Dim iTab As Integer
Dim iLabel As Integer
Dim numLabels As Integer
Dim totalRecords As Long
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rsTable As DAO.Recordset
Dim rsQuery As DAO.Recordset
' Set query definition for creating recordset
Set db = CurrentDb()
Set qdf = db.QueryDefs("TakeNoticeLabelQuery")
If CurrentProject.AllForms("TakeNoticeForm").IsLoaded Then
qdf.Parameters("[Forms]![TakeNoticeForm]![FirstDBTextbox]") = [Forms]![TakeNoticeForm]![FirstDBTextbox]
qdf.Parameters("[Forms]![TakeNoticeForm]![LastDBTextbox]") = [Forms]![TakeNoticeForm]![LastDBTextbox]
qdf.Parameters("[Forms]![TakeNoticeForm]![CountyCombobox]") = [Forms]![TakeNoticeForm]![CountyCombobox]
qdf.Parameters("[Forms]![TakeNoticeForm]![TaxYearTextbox]") = [Forms]![TakeNoticeForm]![TaxYearTextbox]
' qdf.Parameters("[Forms]![TakeNoticeForm]![TakeNoticeDateTextbox]") = [Forms]![TakeNoticeForm]![TakeNoticeDateTextbox]
Else
qdf.Parameters("[Forms]![TakeNoticeForm]![FirstDBTextbox]") = ""
qdf.Parameters("[Forms]![TakeNoticeForm]![LastDBTextbox]") = ""
qdf.Parameters("[Forms]![TakeNoticeForm]![CountyCombobox]") = ""
qdf.Parameters("[Forms]![TakeNoticeForm]![TaxYearTextbox]") = ""
' qdf.Parameters("[Forms]![TakeNoticeForm]![TakeNoticeDateTextbox]") = CStr(Date)
End If
Set rsQuery = qdf.OpenRecordset
rsQuery.MoveLast
totalRecords = rsQuery.RecordCount
'Close and delete records from TemporaryTNLabels table.
DoCmd.SetWarnings False
DoCmd.Close acTable, "TemporaryTNLabels"
DoCmd.RunSQL "DELETE FROM [TemporaryTNLabels]"
DoCmd.SetWarnings True
numLabels = Me.NumLabelsTextbox
MsgBox numLabels & " labels"
'Open a table-type Recordset
Set rsTable = db.OpenRecordset("TemporaryTNLabels", dbOpenTable)
rsQuery.MoveFirst
With rsTable
For iTab = 1 To totalRecords
For iLabel = 1 To numLabels
Debug.Print rsQuery!DatabaseID
.AddNew
!ParcelNumber = rsQuery!ParcelNumber
.Update ' <-------------------------This is where the error points.
.Bookmark = .LastModified
Next iLabel
rsQuery.MoveNext
Next iTab
End With
' DoCmd.OpenReport ReportName:="TakeNoticeLabelReport", View:=acViewPreview
rsTable.Close
Set rsQuery = Nothing
Set qdf = Nothing
Set db = Nothing
End Sub
This is why I stopped using lookup fields :-( I would delete the table TemporaryTNLabels or rename it to TemporaryTNLabels_OLD. Then recreate the table TemporaryTNLabels from scratch with only one field ParcelNumber, and start from there.

How to update a selection of SQL records from Access VB?

I'm looking for help in creating the simplest method of doing the following update on a selection of items.
I have a table in SQL called Item with field ReservationID
I have a list of items in Access and what I'd like to do is select items using the record selectors in the Access form and update those items with the ReservationID using an SQL Update command.
I read somewhere that only adjacent record selectors could be selected which is fine but I don't really know where to begin.
Any pointers would be gratefully received. Thanks.
---23/02/2017---
Ok I changed it from a function to a Private Sub thus:
Private Sub cmdReserve_Click()
Dim i As Long
Dim frm As Form
Dim rs As DAO.Recordset
' Get the form and its recordset.
Set frm = Forms![F_SalesOrders_ItemsInStock]
Set rs = frm.RecordsetClone
' Move to the first record in the recordset.
rs.MoveFirst
' Move to the first selected record.
rs.Move frm.SelTop - 1
' Enumerate the list of selected records
' presenting the field contents in a message box.
For i = 1 To frm.SelHeight
MsgBox rs![ItemID]
rs.MoveNext
Next i
End Sub
but when I select records and hit the button nothing happens
Consider a linked table and walking the record set.
Function DisplaySelectedCompanyNames()
Dim i As Long
Dim frm As Form
Dim rs As DAO.Recordset
' Get the form and its recordset.
Set frm = Forms![Customers]
Set rs = frm.RecordsetClone
' Move to the first record in the recordset.
rs.MoveFirst
' Move to the first selected record.
rs.Move frm.SelTop - 1
' Enumerate the list of selected records presenting
' the CompanyName field in a message box.
For i = 1 To frm.SelHeight
MsgBox rs![CompanyName]
rs.MoveNext
Next i
End Function