OpenRecordSet too few parameters 4 / issues with QueryDefs - vb.net

Issue: I have a form (frm_input) where a user inputs a population range. Once the user enters the min and max of the range and clicks the 'ok' button, the values are input into a query (qryMasterQuery) and the query is run based on these inputs using a 'Between' statement referencing the fields in the form.
The ‘OK’ button also open another form ‘frm_output’. This form runs a function ‘percentile’ that calculates the percentiles of data in the query. The function is passed three parameters – the query name, the field within the query on which to calculate the percentile and the percentile to calculate.
The function and form run fine when I omit the "between" statements from the query. When I tried to tie it all together I received a 'too few parameters, 4' on my OpenRecordset() function. From what I've read I need to explicitly declare the DAO.Querydef object
and supply the parameters via the Querydef objects parameters collection.
Issue 1: When I include the statement:
Set qdf = db.QueryDefs("qryMasterQuery")
I get a runtime 424 error message.
Much Bigger Issue 2:
I am still unclear on the sytax for supplying parameters via qdf.Paramaters. I don't want to declare everything in the query, only what's being passed to the function, i.e., the 'fldName'.
my code is below:
Public Function PercentileRst(RstName As String, fldName As String, PercentileValue As Double) As Double
'This function will calculate the percentile of a recordset.
Dim PercentileTemp As Double
Dim dbs As DAO.database
Dim RstOrig As DAO.Recordset
Set dbs = CurrentDb
Dim xVal As Double
Dim iRec As Long
Dim i As Long
Set RstOrig = CurrentDb.OpenRecordset("qryMasterFee", dbOpenDynaset)
RstOrig.Sort = fldName
Dim RstSorted As Recordset
Set RstSorted = RstOrig.OpenRecordset()
RstSorted.MoveLast
RstSorted.MoveFirst
xVal = ((RstSorted.RecordCount - 1) * PercentileValue) + 1
'x now contains the record number we are looking for.
'Note x may not be whole number
iRec = Int(xVal)
xVal = xVal - iRec
'i now contains first record to look at and
'x contains diff to next record
RstSorted.Move iRec - 1
PercentileTemp = RstSorted(fldName)
If xVal > 0 Then
RstSorted.MoveNext
PercentileTemp = ((RstSorted(fldName) - PercentileTemp) * xVal) + PercentileTemp
End If
RstSorted.Close
RstOrig.Close
Set RstSorted = Nothing
Set RstOrig = Nothing
Set dbs = Nothing
PercentileRst = PercentileTemp
End Function
I am eternally greatful for any help as I am just about done banging me head on the wall.

First a couple style tips. Dimension all your variables at the top of the function. And you can make your code text to look like code by surrounding by backticks like so or putting 4 spaces in front of each separate line.
Like so
You should not need to make a new sorted Recordset, as setting the Sort property will sort it.
Issue 1:
Don't forget to declare the QueryDef variable. Also, you missed the s in your Database variable dbs. Double-check qryMasterQuery is the right name.
Dim qdf as QueryDef
Set qdf = dbs.QueryDefs("qryMasterQuery")
See MSDN for more info.
Issue 2:
You will need to supply the parameters for the query to work. That explains the 'Too few parameters' error. The method is as follows:
Dim qdf as QueryDef
Set qdf = dbs.QueryDefs("qryMasterQuery")
qdf.Parameters("Prmtr1") = "blah" 'You can also use qdf.Parameters!Prmtr1 = "blah"
qdf.Parameters("Prmtr2") = 1234
set rstOrig = qdf.OpenRecordSet()
An alternative to supplying parameters is removing them from the query or creating a new query with the implied parameters already supplied.
See the Parameters MSDN for more info. Note the example is hard to follow and uses different methods.

Related

Database sum() values together if string matches in VBA

Sorry for the basic question, I've spent the best part of a hour figuring this out and I'm at my limit. I'm trying to add all values together if a string matches a certain size, for context I'm adding wall tiles together for a client, here's an example table;
Code
TileSize
TileQty
BG3215
8mm
1
BG3545
10mm
3
BG3246
8mm
4
BG3745
8mm
1
BG3255
12mm
2
My VBA:
Dim db As DAO.Database
Set db = CurrentDb
Dim eight As DAO.Recordset
Dim strSQLeight As String
strSQLeight= "SELECT SUM(TileQty) FROM PickQuery WHERE TileSize = '8mm'"
Set eight= db.OpenRecordset(strSQLeight)
'Error line ^
sometextbox = eight.Fields(0).Value
Run-Time error:
Too few parameters expected 3
Intended result is to return 6 (6 x "8mm" strings)
I assume there should be another argument in there but after looking in stack overflow and on google for help, I can't see another way to write this.
Your code works perfectly for me (running in an MSAccess DB, vba module):
Sub foo()
Dim db As DAO.Database
Set db = CurrentDb
Dim eight As DAO.Recordset
Dim strSQLeight As String
strSQLeight = "SELECT SUM(TileQty) FROM PickQuery WHERE TileSize = '8mm'"
Set eight = db.OpenRecordset(strSQLeight)
sometextbox = eight.Fields(0).Value
End Sub
Is there something we are missing? How are you running this code? Is it in an access vba module? Somewhere else?
Too few parameters expected 3
This means, that your query PickQuery is missing three parameter values.
Most likely, these are values fetched from the form where you call this code.

Unable to access records in DAO Recordset

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.)

vba store recordset as integer variable

First time poster, I finally had a question that I couldn't find an answer to here.
I have an MS Access query that returns 1 result (which is a number) that I want to store as an integer variable (x) so I can use it later for a loop. The issue is that because I'm using it as a recordset and the variable is an integer, I'm receiving a "Type Mismatch" error.
Right now I'm just storing the result to a cell and setting the variable equal to the cell:
Ws.Range("A1") = Db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").GetRows(1)
x = Ws.Range("A1")
Ws.Range("A1").Delete
And then later I just have a loop that runs x times:
For i = 0 To x
Basically, I just want to have some code that looks like this:
x = Db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").GetRows(1)
Any help here would be huge. Thank you!
The following should give you the correct result:
Dim x As Integer
Dim db As DAO.Recordset
db.MoveFirst
If IsNumeric(db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").Fields(0).Value) Then
x = CInt(db.OpenRecordset("SELECT COUNT(Asset_Name) FROM Assets WHERE Active = True").Fields(0).Value)
Else
MsgBox "The query did not return a number." & Chr(10) & "Aborting..."
End If
Note, that you are using DAO and not ADO as your original tags on the post indicated. Still, they both behave rather similar and the cursor is normally on the first row (when the data is returned). So, MoveFirst should not be necessary. Still, Microsoft themselves keep using it in its own sample code all the time. The first column if for DAO and ADO alike .Fields(0).

Populating reports with calculated values

I hope this is a simple question and you don't have to waste too much of you time on it.
I have an report (called repRAD78) which contains a textbox (called txtRAD8). I would like to populate txtRAD8 with a calculated value based on numbers pulled from a query called qryrRAD78.
Looking through the forums it looks like recordsets would be the solution but this is my first foray into recordsets and it's not going well. :(
The code I have pasted in below I have pulled together from a number of places and it doesn't produce any errors but puts the same value into txtRAD8 for all the records.
I'm sorry if this is a stupid question but it's been driving me potty.
Many thanks for your time.
Al.
Public Sub Calc()
Dim dbs As DAO.Database
Dim rst As DAO.Recordset
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("qryrRAD78")
rst.MoveFirst
Do Until rst.EOF = True
Dim lngMean As Long
Dim lngRAD78max As Long
Dim lngRAD78_1 As Long
Dim lngRAD78_2 As Long
Dim lngRAD78_3 As Long
Dim lngRAD7 As Long
Dim lngRAD8 As Long
lngRAD78_1 = rst![RAD78_1]
lngRAD78_2 = rst![RAD78_2]
lngRAD78_3 = rst![RAD78_3]
lngRAD8b_c = rst![RAD8b_c]
lngMean = (lngRAD78_1 + lngRAD78_2 + lngRAD78_3) / 3
lngRAD78max = Maximum(Abs(lngRAD78_1), Abs(lngRAD78_2), Abs(lngRAD78_3))
lngRAD7 = ((lngRAD78max - lngMean) / lngMean) * 100
lngRAD8 = ((lngMean - lngRAD8b_c) / lngRAD8b_c) * 100
txtRAD8.Value = lngRAD8
rst.MoveNext
Loop
rst.Close
dbs.Close
End Sub
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Calc
End Sub
Here's a second approach to this. Rather than using a function in the code, take the calculations from your Calc() routine and put them in another query.
SELECT idrRAD78,
(RAD78_1 + RAD78_2 + RAD78_3) AS Mean,
(IIf(Abs(RAD78_1) > Abs(RAD78_2),
IIf(Abs(RAD78_1) > Abs(RAD78_3), RAD78_1, RAD78_3),
IIf(Abs(RAD78_2) > Abs(RAD78_3), RAD78_2, RAD78_3))) AS RAD78Max,
(((RAD78max - Mean) / Mean) * 100) AS RAD7,
(((Mean - RAD8b_c) / RAD8b_c) * 100) AS RAD8
FROM qryrRAD78
This will give you a query that performs the same calculations as your existing function. Then just edit the report query to join to this new query (just like joining a table) using something like:
FROM ReportQuery INNER JOIN NewQuery ON ReportQuery.idrRAD78 = NewQuery.idrRAD78
Change the query names to match the real names. Add the fields from the new query in the SELECT part of your report query:
SELECT <existing field list>, RAD7, RAD8
Then set txtRAD8 to the RAD8 field.
I'm just doing this from memory as I'm not in front of my own computer, but hopefully that makes sense and is close enough to the correct code.
The problem with this function is that every row on the report is going to have a textbox called txtRAD8. So what you are really doing is updating every textbox on the report with the same value (once for every loop through the recordset). You are not actually setting the value for each individual row.
What you need to do is make the value of the textbox = Calc(RowID). Then your query uses the passed-in parameter to get the value for that one record instead of looping through the whole recordset, and updates just that one row on the report.
So your Sub becomes a Function, and returns the calculated value.

Prompted for input twice in query

Hoping someone can shed some light on a problem I'm having with vb and Access. The general issue is this:
There is a form that supplies user input to a query
The query runs with the user input from the form
A report is generated that relies on a vb module to generate percentiles from the query.
Basically the form provides input to a query, which in turn provides input to a module within a report.
The issue I am having is that the user enters input once on the form and then is prompted (with pop-up windows) to enter the data again. Only the data from the second go-around is reflected on the report. Is there a way to have the form data remain and the query not be prompted for it again?
Below is my code from the module (in the report). As you'll see I attempt to pass the parameters from the form but it doesn't seem to be working:
Public Function PercentileRst(RstName As String, fldName As String, PercentileValue As
Double) As Double
'This function will calculate the percentile of a recordset.
Dim PercentileTemp As Double
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim RstOrig As DAO.Recordset
Dim RstSorted As DAO.Recordset
Dim xVal As Double
Dim iRec As Long
Dim i As Long
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs("qryMaster")
'i need to pass the parameters to the query
qdf.Parameters!minA = Forms!demo_form.min_assets
qdf.Parameters!maxA = Forms!demo_form.max_assets
qdf.Parameters!minP = Forms!demo_form.min_parts
qdf.Parameters!maxP = Forms!demo_form.max_parts
Set RstOrig = qdf.OpenRecordset()
RstOrig.Sort = fldName
Set RstSorted = RstOrig.OpenRecordset()
RstSorted.MoveLast
RstSorted.MoveFirst
xVal = ((RstSorted.RecordCount - 1) * PercentileValue) + 1
'x now contains the record number we are looking for.
'Note x may not be whole number
iRec = Int(xVal)
xVal = xVal - iRec
'i now contains first record to look at and
'x contains diff to next record
RstSorted.Move iRec - 1
PercentileTemp = RstSorted(fldName)
If xVal > 0 Then
RstSorted.MoveNext
PercentileTemp = ((RstSorted(fldName) - PercentileTemp) * xVal) + PercentileTemp
End If
RstSorted.Close
RstOrig.Close
Set RstSorted = Nothing
Set RstOrig = Nothing
Set dbs = Nothing
PercentileRst = PercentileTemp
End Function
The form I am using passes 4 parameters to the query. Within the query I use the following criteria: 'Between [minA] And [maxA]' and 'Between [minP] And [maxP]'
Is there some way in the query's SQL to initialize the values of these parameters to the values in the form?
The form is opens the query and the report when the user clicks 'OK'.
qryMaster includes parameters and is the report's record source. Therefore when the report first opens, Access asks the user to supply values for those parameters.
Later, you use qryMaster again in a procedure which loads its result set into a DAO.Recordset. At that time your code supplies values for the parameters, so the user is not asked to supply values a second time. However, that doesn't have any effect on the situation at form open.
Try a revised qryMaster where you point to the form's controls:
WHERE
some_field BETWEEN Forms!demo_form!min_assets
AND Forms!demo_form!max_assets
AND another_field BETWEEN Forms!demo_form!min_parts
AND Forms!demo_form!max_parts
The db engine can look at those controls on demo_form to get the values it needs, so won't ask the user to supply parameter values separately.