All right, i've got it. the Immediate window wasn't displayed. it's looking
for the following:
Forms!UserIDHiddenForm!Text0
which is a call to the GetUserID() function, which simply returns the
shortname of the user. the shortname gets checked on a table to see whether
it exists. So how do i feed that into Countofuserexistingrecords... as a
parameter so that it has what it needs to complete its recordset?
Incidentally, if i understood correctly, using dlookup would circumvent this
problem because it takes care of everything required to run the lookup?
:
Your GetUserID function almost certainly calls the Widows API GetUserName
function, so I think we can rule that out as the mysterious parameter.
A query doesn't have to be open when the DLookup function (or any other
domain function such as DCount, DMax etc) is called.
If you create a recordset object based on a query then its Fields collection
is the set of columns returned by the query, so it does in effect "adopt the
field names". You cannot refer directly to the value of a field returned by
a query; you either have to create a recordset object (as my sample
OpenRstFromQuery procedure does) or use one of the domain function such as
DLookup.
But we are getting away from the original problem of what is the expected
parameter. You should be able to list the parameters for the SQL statement
with the following function:
Public Sub ListParameters(strSQL As String)
Dim dbs As DAO.Database, qdf As DAO.QueryDef
Dim prm As DAO.Parameter
Set dbs = CurrentDb
Set qdf = dbs.CreateQueryDef("", strSQL)
For Each prm In qdf.Parameters
Debug.Print prm.Name
Next prm
End Sub
Call it like so:
ListParameters "SELECT * FROM CountOfUserExistingRecords"
Any parameters expected by the CountOfUserExistingRecords query should be
listed to the debug window. This should point you in the direction of the
cause of the problem, and hopefully to a solution.
Ken Sheridan
Stafford, England
:
i'm using a GetUserID() public function built with the help of the users
here, and yes i believe it uses the windows API.
Does dlookup instantiate the query on its own, or does it require the query
is running when it is called?
as for the column name, yes, that is how its referred to by me, i was
unsure if that was correct. Does the recordset object adopt the field names
of the thing it contains, or is it still proper to refer to the name of the
query itself thats being run?
In addition, is the way i've contstructed it improper, or is dlookup just
more efficient, faster, etc?
:
How are you getting the current user's login name for the query? If you are
calling the Windows API GetUserName function that's not a parameter so should
be OK, but if you are getting it in some other way its possible it could be
being treated as a parameter.
Rather than creating recordset objects why not use the DLookup function to
get the value of any non-Null column from a query? Test for
IsNull(DLookup("ColumnName","QueryName")) to identify no rows returned, and
for DLookup("ColumnName","QueryName") = 0 to identify where the Count
operator returns a 0.
BTW don't use recordcount as an object variable's name; it’s a property name
in both DAO and ADO so should be avoided.
I also note that you refer to recordCount!RecordNum <= 0, but in the SQL
statement the column name is CountOfRecordNum.
Ken Sheridan
Stafford, England
:
I've had the same trouble with the openquery method. Perhaps we could try
that instead. Here, let me post the code, and yes, the query i'm trying to
run does refer to a value based on a second table. Here:
Public Function testfunction()
Dim adminQuery As Recordset
Dim processorQuery As Recordset
Dim recordCount As Recordset
Set adminQuery = CurrentDb.OpenRecordset("IsAdminQuery")
Set processorQuery = CurrentDb.OpenRecordset("IsProcessorQuery")
'Set recordCount = CurrentDb.OpenRecordset("CountOfUserExistingRecords")
If (adminQuery.BOF And adminQuery.EOF) Then
If (processorQuery.BOF And processorQuery.EOF) Then
DoCmd.Close
ElseIf (recordCount!RecordNum <= 0) Then
DoCmd.OpenForm ("Costpoint Processor New Record")
Else: DoCmd.OpenForm ("ReversalCostpoint Processor")
End If
Else: DoCmd.OpenForm ("Costpoint Reversals")
End If
End Function
The count of user existing records query is the problem. It looks like this:
SELECT Count(ReversalMemo.RecordNum) AS CountOfRecordNum
FROM ReversalMemo, UserIDQuery_SN_to_ProcName
HAVING
(((ReversalMemo.Signee1)=[UserIDQuery_SN_to_ProcName].[ProcessorName]));
The user_sn... query produces a user's true name based on a shortname from
their login. It's later used to filter their records. The purpose of this
particular part of the function is, if the user is listed as a processor, but
has 0 records (null or 0 result) the form opens up the new record form
instead of the processor form, which would be a blank white page since its
not for data entry.
Its basically a very simple decision tree. Is the user an admin? if yes,
open admin version. if no, is the user a processor? if yes, open the
processor form, showing them only their own records. if no, close. if the
processor is valid but has no records, start a new record.
The count of user records query uses two seperate tables in the same query
to determine if the record count. Running it through VB, it expects a
parameter value for the criteria i've set, since its not: concurrently
running, can't be determined without checking the row value determined by the
other query (user_sn_to...), I suppose, or explicitly defined. What else
can i provide that might help you see what i'm trying to accomplish, and the
simplest way to do it?
I'd also been advised to try a make-table query, to put the two values in
one table so that they could be easily read, but i can't compact on exit,
because i do not own the drive priveledges where the database is served, so i
would be left with lots of bloating
:
A parameter is a variable which a query can use in a number of ways, but most
frequently it restricts the rows returned. This is what a simple prompt of
the type you are probably used to does, but it can also be a reference to a
control on a form. Take a look at the Sales by Year query in the sample
Northwind database which comes with Access; this includes the criterion on
the ShippedDate column:
Is Not Null And Between [Forms]![Sales by Year Dialog]![BeginningDate] And
[Forms]![Sales by Year Dialog]![EndingDate]
The references to the [Forms]![Sales by Year Dialog]![BeginningDate] and
[Forms]![Sales by Year Dialog]![EndingDate]controls are parameters. The
procedure I sent you will work with a query containing this type of parameter
because it can be evaluated by the Eval function. A simple prompt would not
work, however, because that cannot be evaluated. If you look at the Sales
by Year query in SQL view you'll notice that the parameters are declared as
DateTime at the start of the SQL statement. In my experience people often
omit to do this, but with dates its actually quite important as otherwise a
parameter value entered as a date in short date format could be
misinterpreted as an arithmetical expression.
I'm not sure what you have in mind when you say "its provided by a second
table". A value in a column in another table is not a parameter.
One common cause of a 'parameter expected' error is because users
incorporate a reference to a control on a form in a literal SQL string in
code, e.g "WHERE LastName = Forms!MyForm!txtLastName". What should be done
in a case like that is to concatenate the value of the control into the SQL
string; "WHERE LastName = """ & Forms!MyForm!txtLastName & """". That's not
the case with the SQL you posted, however. The most likely culprit is a
parameter in the UserIDQuery_SN_to_ProcName, and my function would handle
that. Sometimes the error is just a result of a simple typo. If a column
name is entered in the string incorrectly Access will treat it as a
parameter; essentially anything it doesn't recognize as an object is treated
as a parameter. However, you say that the query opens fine using the same
SQL as a query rather than in code, which suggests there is no typo.
The fact that its opening as a query does beg the question why you want to
build and open via VBA at all. Why not just save the query and open it with
the OpenQuery method?
A querydef object is an object which defines a query (its short for 'query
definition'). Saved queries are querydef objects in the current databases
querydefs collection. A querydef object does not have to be a saved query,
however. One can be temporarily created in code. This is commonly done and
its rows accessed by means of a recordset object created with the
OpenRecordset method of the querydef object. In my function a querydef
object is created with the CreateQueryDef method of the database object and
saved by giving it name. Its then opened in datasheet view with the
OpenQuery method and finally deleted from the current databases querydefs
collection. So its not quite as temporary as a true temporary querydef
object.
As a simple example paste the following procedure into a standard module:
Public Sub OpenRstFromQuery(strQuery As String)
Dim dbs As DAO.Database, qdf As DAO.QueryDef
Dim prm As DAO.Parameter, rst As DAO.Recordset
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs(strQuery)
For Each prm In qdf.Parameters
prm = Eval(prm.Name)
Next prm
Set rst = qdf.OpenRecordset
With rst
Do While Not .EOF
Debug.Print .Fields(0); .Fields(1)
.MoveNext
Loop
End With
End Sub
Then in the debug window (aka immediate window) call it, passing it the name
of any simple query with at least two columns returned like so:
OpenRstFromQuery "NameOfQueryGoesHere"
You'll see that it lists the values from first two columns of the query to
the debug window.
Ken Sheridan
Stafford, England
:
oh wow. I understand what you're stating and the logic of it, but not all of
the code, i'll definately need some help with this. So the parameter i'm
speaking of is not one that pops up, requesting a parameter... its provided
by a second table, its never explicitly entered by the user. Does that
change anything? or perhaps i'm misunderstanding what you've stated.