views:

356

answers:

2

Hi there,

I would like to know if there is a way to set the parameters in an Access 2007 query using VBA. I am new to using VBA in Access, and I have been tasked with adding a little piece of functionality to an existing app.

The issue I am having is that the same report can be called in two different places in the application. The first being on a command button on a data entry form, the other from a switchboard button. The report itself is based on a parameter query that has requires the user to enter a Supplier ID.

The user would like to not have to enter the Supplier ID on the data entry form (since the form displays the Supplier ID already), but from the switchboard, they would like to be prompted to enter a Supplier ID.

Where I am stuck is how to call the report's query (in the report's open event) and pass the SupplierID from the form as the parameter. I have been trying for a while, and I can't get anything to work correctly. Here is my code so far, but I am obviously stumped.

Private Sub Report_Open(Cancel As Integer)

Dim intSupplierCode As Integer

'Check to see if the data entry form is open
If CurrentProject.AllForms("frmExample").IsLoaded = True Then

    'Retrieve the SupplierID from the data entry form
    intSupplierCode = Forms![frmExample]![SupplierID]

    'Call the parameter query passing the SupplierID????
    DoCmd.OpenQuery "qryParams"


Else

    'Execute the parameter query as normal

    DoCmd.OpenQuery "qryParams"?????


End If

End Sub

I've tried Me.SupplierID = intSupplierCode, and although it compiles, it bombs when I run it. And here is my SQL code for the parameter query:

PARAMETERS [Enter Supplier] Long; SELECT Suppliers.SupplierID, Suppliers.CompanyName, Suppliers.ContactName, Suppliers.ContactTitle FROM Suppliers WHERE (((Suppliers.SupplierID)=[Enter Supplier]));

I know there are ways around this problem (and probably an easy way as well) but like I said, my lack of experience using Access and VBA makes things difficult. If any of you could help, that would be great!

+1  A: 

As I outlined in a recent post, I tend never to hardwire any parameters or form control references into the recordsources of reports or forms. Instead, I set them at runtime. The simplest way is by passing the WhereCondition property in the DoCmd.OpenForm/DoCmd.OpenReport:

DoCmd.OpenReport "MyReport", , , "[SupplierID]=" & Me!SupplierID

That assumes you're running it from a form that has the relevant SupplierID already present in its recordsource (i.e., you're on a record with that SupplierID).

More complicated is to use the OnOpen event of the report to set the reports's recordsource. That's what I outlined in the cited post above. But that example hardwires the choice to a selection form, whereas you might want to instead offer different sets of choices depending on context. There are two ways to handle that:

  1. if A2003 and later, pass an OpenArg (the last parameter of the DoCmd.OpenReport) to tell the OnOpen event what to do to collect the information on what to filter to.

  2. use an outside structure like a standalone class module to store criteria that the OnOpen event will read and act upon accordingly.

I suspect that the WhereCondition in the DoCmd.OpenReport is your easiest solution, but if you want details on the other two, just ask.

David-W-Fenton
Thanks for the response David. But I think my lack of experience is really showing, so I must apologize. What I would like to have happen is in the Open event of the Report, issue the parameter prompt of the report's record source query only if the data entry form is not open. If the data entry form is open, just grab the Supplier ID from the form itself. I am still stuck, because no matter what I do, the parameter prompt still shows, or it bombs entirely. I've tried the line of code you've suggested, but I still get prompted for the SupplierID. I am, however, not familiar with the OpenArgs.
JPM
I'm suggesting you remove the parameters entirely from the report's recordsource and instead collect the values you want and supply them in the WhereCondition of the DoCmd.OpenReport. This is much simpler and removes any dependency on outside objects from the reports. It allows you to open the report to show all records, or to filter it to any set of records you like at runtime. Albert has explained it all quite well in his answer.
David-W-Fenton
Thanks David. I brought up this up with my mentor (I'm a College student working on my summer co-op position), and although it makes sense to remove the dependencies that presently exist, the solution was to create two queries, and dependent on whether the data entry form is open, apply the report's record source accordingly. It's ugly, but so is this app. There are absolutely NO naming standards present, and that's if they are even named to begin with. Dealing with a bunch of Text39's and CommandButton291's is making things difficult enough as it is. But in the end, I do what I'm told...
JPM
I'm also a new member here, so I don't have the ability to vote you up just yet, so I will just have to extend my gratitude for now. Thanks again!
JPM
I'm not grubbing for reputation points, just trying to help, so you your thanks is more than enough reward.
David-W-Fenton
You also might want to suggest to your mentor that a useful project for you would be to "refactor" the Access app by converting to reasonable naming conventions. An excellent way to do this is to temporarily turn on Name AutoCorrect, and then alter the field names in the base tables (if the app is split, this will only work if you temporarily import the real tables, do the name changes, and then revert to the linked tables). This would be a good investment in terms of maintainability and expandability for the future, and in my opinion, a good use of a coop student's time.
David-W-Fenton
Thanks David. Any help is greatly appreciated, and unfortunately, I don't have the experience needed to offer any useful advice, so I feel bad that I can't express my gratitude by voting up. But like I said, I really appreciate any help you have given me.I would be interested in doing the refactoring, but the tickets won't stop coming, and from what I've heard from the other programmers is that they are backlogged with enough work to last them 2 years. I guess I will be maintaining this app for the entire summer, as all of my tickets have been for this app. :(
JPM
A: 

The suggestion being made here is to 100% REMOVE the parameter from the query. This not only solves your problem, but then means you can use the query for code, other forms and not have your whole design fall apart because one stupid form is not open (hence the VERY reason for your question).

So, remove the parameters from the query. This also means that your report will now not need some form that already opened. And again, if some silly form is not opened, why should your report fail to work?

So, remove the parameter. Now, in your form that opens the report, it can pass the filter, and more in point use what is a called a "where" clause. This "where" clause is designed in MS-access to solve the problem of having to know ahead of time what kind of parameters and filters you need. It occurs at runtime, and thus MANY DIFFERENT forms can call and open that report.

Now in the form that calls and opens the form, you go:

Docmd.OpenReport "rptSuppliers",acViewPreview, , _
                "SupplierCode = " & me.SupplierCode

So, in the above, the parameter is created on the fly. The great advantage is tomorrow you can have another form open the same report and perhaps filter by region.

In the case of NO where clause being passed and a user simply opening the form, then no filters will be used and no prompts will occur and all records will show. This is probably your best approach.

However if for some strange reason you still deem it REALLY necessary to have some report prompt when one silly form just happens to not be opened, then place the following code in the forms on-open event.

If CurrentProject.AllForms("form1").IsLoaded = False Then
   Me.Filter = "SupplierID = " & InputBox("Enter Supplier ID")
   Me.FilterOn = True
End

However, I would really make efforts to avoid hard coding some silly form name in the reports open event. Not only does this mean your hard coding dependencies of some silly form that is now attached to a report, but if you later on copy that report, or even copy the original form (or even rename any of these objects), then you have to go into the application and hunt about and now find the places you as a developer introduced dependences. This approach can substantially increase the maintenance costs of an application and thus should be advoied.

So, the suggestion here is to dump the parameter query. Simply provide a form or some prompt system to launch the reports. Those forms should prompt the user for the information you wish to filter. Or as in your case the bound form and it current record provides that information. The beauty of this system is now there is no depdancy from the report.

Any form, or even any code down the road is free to pass a pramaeter, and it will not be limited to SupplierID, but can be any type of filter or parameter you wish.

Keep in mind that perhaps the user might not want that form to be open and perhaps they don't want the prompt. With your design and question the user will be forced to enter a parameter value even when launching the report without any forms open and not desiring to be prompted to allow them to view all reocrds in that report.

Albert D. Kallal
I think you're recommendation to never hardwire a reference to a criteria form in the OnOpen is overstated. I do it all the time. In the few cases where I also want to provide some method to bypass the criteria form, I use OpenArgs in A2003 and later, and provide a WhereCondition and check the report's .Filter property in the OnOpen to skip the opening of the form.
David-W-Fenton
Thanks Albert. Your advice was great, but in the end, I was told to go with the solution I mentioned in my comment to David. Anyways, after working on this ticket for a while, it got to the point where the time to make it work as it should be would be too much for the ticket. Then again, this app should just be scrapped and redone since it's a horrible mess...Anyways, thanks again for the advice. As I mentioned in my response to David, I am new here, so I can't vote you up just yet either.
JPM