MS Access - Parameters from report in VBA - sql

If you open a report based on a query with some parameters (e.g. StartDate and EndDate), I know that I can used those parameters in the report as [Reports]![ReportName]![StartDate]. But now I would like to use these parameters in a VBA function, but using the same expression doesn't work for me:
MsgBox [Reports]![Test]![StartDate]
This gives me the error:
Run-time error '2465': Microsoft Access can't find the field
'StartDate' referred to in your expression.

And it never will find it.
I never use dynamic parameterized queries. I use controls on a form to select filter criteria and refer to the controls in the WHERE argument of OpenReport command (same for OpenForm).
DoCmd.OpenReport "Test", , , "[StartDate] = #" & Me.tbxStart & "#"
MsgBox = Me.tbxStart
Or if you really prefer dynamic parameters - the report query parameters can refer to the form controls.
VBA code will not find the parameter but it can find textbox in report that references the parameter and pull the parameter value that way.

If you have a report or form that has a query as its Record Source, you can bind the fields of the query--like StartDate--to controls on the report or form, and get the value(s) of that field in a VBA function by referencing the control. For instance, suppose you have a report named DateReport. If the Record Source of DateReport contains a StartDate field, then you can create a text box on the report--we'll call it StartDateBox--and set its Control Source to "StartDate". Then in VBA, you can get the value of this field for the current record with Report_DateReport.StartDateBox. There may be another way to reference Record Source field values of a form or report without binding them to an control, but I don't have MS Access available right now to test this.

You can do it by using a public variable and changing sql of record source dynamically.
You can store parameter value in public variable before calling the report.
First declare a varaible in a module
eg, Public filtDate as Date
Secondly, assign the parameter value to filtDate before running the report
Then, change sql of records source in the report_open event of report
Private Sub Report_Open(Cancel As Integer)
Me.RecordSource = "SELECT * FROM Test WHERE [StartDate] = #" & filtDate & "#"
MsgBox filtDate
End Sub
Here, the sql of recordsource is dynamically set and parameter value can be used directly.

Related

MS Access 2019: Can't populate a form field using SQL query in VBA

I want to auto-populate a field in my form based on the results of an SQL query. I'm just not sure of the proper syntax to get it to properly read the query. This is what I've got, but it's not returning the value of the query, it's actually just returning the text of the query itself.
Private Sub PurchBatchNo_Enter()
Dim MostRecentPurchBatch As String
MostRecentPurchBatch = "SELECT Max(PurchaseBatchNo) FROM purchases"
Me.PurchBatchNo.Value = MostRecentPurchBatch
End Sub
I'm sure the issue has to do with the quotation marks, but it doesn't work without them either, and I'm not sure how to write it properly.
Thanks for being here for beginners like me!
All your code does is set a variable to a string of characters then attempts to set value of field with that string.
But why would you want to populate field with a value already used in a record? Most likely you need to increment by 1.
To use an SQL statement, would have to open a recordset object then reference field of recordset.
Private Sub PurchBatchNo_Enter()
Dim MostRecentPurchBatch As DAO.Recordset
If IsNull(Me.PurchBatchNo) Then
Set MostRecentPurchBatch = CurrentDb.OpenRecordset("SELECT Max(PurchaseBatchNo) AS MaxBatch FROM purchases")
Me.PurchBatchNo = MostRecentPurchBatch!MaxBatch + 1
End If
End Sub
However, pulling a single value from table is what domain aggregate functions are good for.
Private Sub PurchBatchNo_Enter()
If IsNull(Me.PurchBatchNo) Then Me.PurchBatchNo = DMax("PurchaseBatchNo", "purchases") + 1
End Sub
Instead of using VBA procedure, consider just setting DefaultValue property of textbox bound to PurchBatchNo field with the DMax() expression. As soon as record is initiated by input to another textbox, the PurchBatchNo will populate.
If user should not be able to edit this value, set textbox as Locked Yes and TabStop No and use a different event for the VBA code if you go with VBA.

Access button to open multiple reports depending on user input

I am new to access so this might be an easy task or I am just trying to tackle it wrongly. I have a report that has various columns, sample id, sample time, sample type, dry matter, moisture. I am trying to create a button that has an input box for the user to chose what column to sort the report by. So far I thought of creating various reports that have been sorted by each column, named the reports by the column that sorts them then I am trying to have the open report action have a parameter that opens the report linked to the column entered at the input box. Is this even possible or is there a workaround for this.
PS. I am avoiding creating various buttons since it will fill up the screen.
Okay, this is pretty generic and will require some tweaking but it shows the core of how to do this.
To start with you need a module (so not form/report code). This is where the globals will be assigned values:
Option Compare Database
Option Explicit
Global rptname As String
Global fldname As String
Sub setRptName(name As String)
rptname = "Report Sorted by: " & name
fldname = name
End Sub
You will call that code inside the Click() event of your command button on your form and then open the report after that. This will take a combo box value and pass that value to the module code, creating the two global variables.:
Private Sub cmd_report_Click()
mdl_Globals.setRptName Me.cmb_fields.Value
DoCmd.OpenReport "Report1", acViewPreview
End Sub
I'm unsure if this will work with non-preview views, but you probably want preview anyway.
Lastly in the report code behind, you need the Load() and open() events, you may be able to get it to work with both inside one or other but I know this one works.
So to set the caption:
Private Sub Report_Load()
Me.lbl_header.Caption = rptname
End Sub
And then to sort:
Private Sub report_open(Cancel As Integer)
Me.Report.OrderBy = "[" & fldname & "]"
Me.Report.OrderByOn = True
End Sub
If your entry box on the form does not have entries that exactly match the name(s) of the fields in the table you will get a parameter popup.

MS access check column value and change another

I have an ms access database with some yes/no columns I want to check and set the value of a third. The statement should be something like the following
if !col1 && !col2:
col3 = no
else:
col3= yes
I keep searching but don't really understand vba and can't find what I need .. Mostly a segment of an answer to something else that I cant make work. Currently trying to create it in the "module" section is that even right? Would be best if this could be done automatically as those columns are changed or maybe run once and do all rows. Please help me get on the right track, any help greatly appreciated.
Here is what I would do:
1- Create a form and add at least one command button on it. Name it cmdMyButton or cmdAnythingThatYouWant (cmd is the prefix used in examples from Microsoft for command buttons)
2- in the design view, double click the command button so to pop the code window
3- In the onClick() function, write the code that opens up a recordset for your table, loop through records and for each row, verify the value of those 2 columns and update if needed. (look at the documentation for DAO.recordset)
Let's say you have an Access table named Table1, with some Access fields:
The following Access SQL statement will update the value of col3 based on the values of col1 and col2, for every row in Table1:
UPDATE Table1
SET col3 = NOT col1 AND NOT col2
There are a number of ways to leverage this SQL statement:
You can paste it into the Query Designer in SQL view, and execute it via the Access UI
You can run it as part of an Access macro
You can execute it in VBA, using ADO or DAO
You can execute it in VBA, using the DoCmd.RunSQL method
Instead of VBA, you can use another Automation-supporting programming language
I would just create this on a calculated column in your DB table. See screen shot below:
Notice in the properties I set a formula to acquire the desired results based on the first 2 columns. The "Result type" is set to yes/no to mimic the yes/no field. Only difference is, the third column will display a -1 (True) or 0 (False). but when displaying this information on a form, you can have it display the information in a checkbox fashion. The calculated field is also ideal cause it will only update the third column when the target record is updated, not updating the whole table, very useful if the table size starts holding over 100k records.
If you want a VBA code, then you will need a trigger. I'm assuming its a button on the form, if not, you can always change the below code to match the event you want it triggered on. The below code is also a module that can be called/used for any trigger. The code is also assuming you have a primary key.
Public Sub UpdateThirdColumn(ByVal RecordPK As String) 'RecordPK is a passed variable
'that is the primary key identifier to find the
'record in the table
'Set variavble name for SQL statement, gives you one place to update instead of hunting through code
Dim strSQL As String
'Creates the SQL string in the variable assigned
strSQL = "UPDATE {YourTableNameHere} " & _
"SET {YourThirdFieldNAmeHere} = True " & _
"WHERE ((({YourFirstFieldNAmeHere}) = True AND ({YourSecondFieldNAmeHere}) = True AND ({YourPrimaryKeyFieldHere}) ='" & RecordPK & "'));"
'Executes the SQL statement, dbFailOnError will fail if problem exists in SQL statement
CurrentDb.Execute strSQL, dbFailOnError
End Sub
'Use this code if you have a button to trigger event
Private Sub YourButton_Click()
Call UpdateThirdColumn(Me.YourPrimaryKeyControlName)
End Sub
'Use the bottom 2 codes if you want the update for each check box to be checked and update
Private Sub FirstFieldName_AfterUpdate()
Call UpdateThirdColumn(Me.YourPrimaryKeyControlName)
End Sub
Private Sub SecondFieldName_AfterUpdate()
Call UpdateThirdColumn(Me.YourPrimaryKeyControlName)
End Sub
Let me know if you need more assistance or explanation and I will be glad to help.

Data type mismatch when using a Select Query to feed a combo box

I am getting a 'data type mismatch in criteria expression (error 3464) with the below routine when trying to activate drop down box 'cboColleagues'.
In short, there are two combo boxes of which the second one ('cboColleagues') is not visible until the user activates the first ('cboEditPersonnel'). The following routine is created to feed the second combo box with the data source however the error 3464 message appears.
Private Sub cboEditPersonnel_AfterUpdate()
If cboEditPersonnel = "Add Colleague" Then
sql_get = "SELECT tblContacts.CompleteName, tblContacts.Team FROM tblContacts WHERE [tblContacts].[Team]<>'" & Form_frmStaticDataDepartments01.cboDepartments & "'"
Me.cboColleagues.RowSource = sql_get
cboColleagues.Visible = True
Else
End If
End Sub
"Data type mismatch when using a Select Query to feed a combo box" usually this error is related to different type used in attribution and in comparison operator so can you tell me which one is the data type of [tblContacts].[Team] and the data type being returned from the combobox Form_frmStaticDataDepartments01.cboDepartments
After looking at it I can say that you are comparing assuming it's string (text).
additionally you can add your tblContacts design and tblDepartment at for related columns beign used on your script error.
Try to check it.

Is there a way to make UDF that gives a description like the native Excel functions have when user clicks the Fx button?

If I type =vlookup( (or any other native Excel function) in the formula bar and then click the little Fx button to the left of the formula I get a Function Arguments prompt with all the available arguments. In that prompt, below the functional arguments, is a one or two sentence description of the function and of each argument as you move your cursor from each argument's input box.
When I type in the name of my UDF and click the Fx I get an input box for all of my arguments but that is it. Is there a way I can add those same helpful type of descriptions that native Excel functions have?
Type =FormulaName( into a cell and then press Ctrl+Shift+A and it will fill in the reference name of the arguments
I suggest further investigating the Application.MacroOptions method. That method allows you to provide not only a description for the function, but also a description for each of the arguments. For example, if you have a function called "SampleFunction" that takes two arguments, you can run the following and it will set you up nicely for using the fx button with your function.:
Private Sub RegisterMyFunction()
Application.MacroOptions _
Macro:="SampleFunction", _
Description:="calculates a result based on provided inputs", _
Category:="My UDF Category", _
ArgumentDescriptions:=Array( _
"is the first argument. tell the user what it does", _
"is the second argument. tell the user what it does")
End Sub
Yes, there is a somewhat hidden way to do that:
After you defined your UDF in VBA, go to the Object Browser in the Visual Basic Editor (F2). Here, in the top drop down, select VBAProject. In the window below, navigate to your UDF and right click it - select Properties:
In the properties, you can provide the description.
If you need further information, e.g. how to add the function to a certain category check out this OzGrid article!
Create function like I have created below: Function CompanyNames:
Function CompanyNames(CompanyCode As Integer, Data As Range) As String
CompanyNames = WorksheetFunction.VLookup(CompanyCode, Data, 2, False)
End Function
Run below code once and you get the argument description in Function
Sub DescribeFunction()
Dim FuncName As String
Dim FuncDesc As String
Dim Category As String
Dim ArgDesc(1 To 2) As String
FuncName = "CompanyNames"
FuncDesc = "Returns the Company Name"
ArgDesc(1) = "Provide the Company Code"
ArgDesc(2) = "Select Range to lookup"
Application.MacroOptions _
Macro:=FuncName, _
Description:=FuncDesc, _
Category:=Category, _
ArgumentDescriptions:=ArgDesc
End Sub
EDIT
I just noted you are creating UDFs in VBA thus my reply may not be applicable to your situation.
Have a look at one of the sample projects in Excel SDK called Generic.
It is a bare minimum skeleton to build upon
Right after the header include statements, you will notice a declaration of a two dimensional array where the rows represent the number of UDFs in your XLL and the columns are used for the description of the particular UDF
The first column is used for the name of UDF followed by the a string that contains the letters that represent the data type of each parameter in your UDF.
These columns may be used to put description text for each of your parameters in UDFs
The number of columns are determined by the UDF that has the largest number of parameters and the UDFs that have fewer parameters use empty strings as values that are beyond the number of parameters in such UDFs
But then these descriptions will be displayed in the dialog box that pops up when your click on Fx icon