Wrox Home  
Search P2P Archive for: Go

  Return to Index  

access thread: Re: best way of using forms on Access Project - please advise


Message #1 by "David Chapman" <luckychap@b...> on Wed, 27 Mar 2002 09:20:58 +1030
Roddy,

With 24,000 records your users need a method of selecting the data displayed
on the form. Your example "1 table and 1 form" makes this difficult - as
soon as you open the form it will require all the records on which it is
based, then you are changing the record source which causes a requery.

I always use an introductory form, with a combo or list box from which a
user can select the required record. The row source is a query which returns
only the list and the record ID, and because it is limited info it is fast.
After that, the method you use to display the selected record is up to you.
Wherever possible I use a where clause on the open form because it is faster
than changing the record source. Usually my introductory form is not based
on any table - in one of my aps it served as the start up screen with a
picture and operating instructions.

With 24000 records your users may need a stepped method of selecting a
record, ie a second combo box where the list depends on the users selection
in a prior combo box. But every situation is different and there are a
thousand ways to skin a cat.

David




-----Original Message-----
From: Roddy Campbell [mailto:scotiwis@b...]
Sent: Tuesday, March 26, 2002 9:55 PM
To: Access
Subject: [access] Re: best way of using forms on Acces Project - please
advise


ok I'll try and be clearer.

Taking 1 table and 1 form as an example.

I have the form displaying the data from the table, users can select
various records by using a dropdown combo box, amend data / add data using
the form.

I have been told various things by various people regarding the best way
to link the table to the form, what I want to know is which is the fastest
method when selecting a record in the combo box for it to display on
screen.

The alternatives are:

1. set the recordsource of the form directly to the table.
problems with this are that when the form is opened for the first time by
a user all 24000 records are loaded into it, the combo box uses "find
record on form" to search through the 24000 records and select one - this
is the client/access side doing all the work.

2. set the recordsource of the form to "select * from [table] where
recordID = combobox afterupdate recordID". The recordsource of the form is
initially set to display 1 record when opened - "select * from [table]
where recordID = 1" - this avoids the need to load 24000 records at
startup - the combobox after update then changes the recordsource of the
form to recordsource = "select * from [table] where recordID = combobox
after update ID. This seems to still be unefficient as Access is
performing the Select statement on the table rather than SQL.

3. set the recordsource of the form to a stored procedure. The stored
procedure code is "select * from [table] where recordID = @inputRecordID".
The table as with 2 opens with recordsource = "select * from [table] where
recordID = 1", the on afterupdate of the combobox triggers the stored
procedure sending it the afterupdate recordID, the returned record from
the stored procedure is then set as the recordsource of the form - this
way SQL is doing all the work and access is just passing parameter and
displaying result on form.

What I want to know is what is best practice out of the 3 above, should
you load all table's records into form then get access to "find a record
on my form" with combo box as with 1, only ever have 1 record loaded into
form and use Access to call SQL code to get a record and display on form
as with 2, or only ever have 1 record loaded on form and get the stored
procedure to return the value of the record you want after update of
combobox.

?



Message #2 by "Roddy Campbell" <scotiwis@b...> on Tue, 26 Mar 2002 23:09:16
Thanks for your reply David.
That sounds like an intersesting idea, I may give it a shot.
Before that though - my method 3 I can't test for performance as I can't 
figure out the code.
I want the afterupdate of the combo box to pass the recordID to the stored 
procedure, and then change the recordsource of the form to the result of 
the stored procedure.

what I have:

after update of combobox:

Private Sub LotNoFind_AfterUpdate()
'Detail.Visible = True
'Dim rs As Object
'    Set rs = Me.Recordset.Clone
'    rs.Find "[CATSGoodsInid] = " & Str(Me![LotNoFind])
'    Me.Bookmark = rs.Bookmark
'    rs.Close
'    Set rs = Nothing

Dim cmd1 As ADODB.Command
Dim prm1 As ADODB.Parameter

Set cmd1 = New ADODB.Command

With cmd1
    .ActiveConnection = CurrentProject.Connection
    .CommandText = "CATSspgGoodsInLookupLot"
    .CommandType = adCmdStoredProc
    Set prm1 = .CreateParameter("@GoodsInid", adInteger, adParamInput, 4)
    .Parameters.Append prm1
    prm1.Value = LotNoFind
End With

Dim rstTest As ADODB.Recordset
Set rstTest = New ADODB.Recordset
    rstTest.Open cmd1
    Me.RecordSource = rstTest     ****returns error "Type Mismatch"

End Sub


the stored procedure:

CREATE PROCEDURE CATSspgGoodsInLookupLot
	(
		@CATSGoodsInid  integer
	)

  AS

SELECT * FROM CATSGoodsIn WHERE CATSGoodsInid = @CATSGoodsInid
GO


The first few lines of the afterupdate combobox are my method 1, ignore 
them time being. I can't figure out why I get a Type Mismatch when running 
the after update on the combobox. Can you see what I'm doing wrong here ?
Message #3 by brian.skelton@b... on Wed, 27 Mar 2002 00:36:25
Hi

I think your basic problem is a missing 'Set':

    Set Me.RecordSource = rstTest

I would also recommend the following changes, just to ensure that the 
recordset is suitable for binding to a form:

     rstTest.CursorLocation = adUseClient
     rstTest.Open cmd1

On the wider issue, I'm (hopefully) coming to the end of a large Access 
Project\SQL Server job, and I went for Method 4!

As in your method 3, I'm using Stored Procedures to return single records, 
letting the server machine do all the hard work. The difference is, I'm 
using totally unbound forms to display the results. The downside is that 
you have to write the code to do all the stuff that Access would usually 
do, such as filling the forms controls and writing any changes back to the 
database. The advantage is that you've got the most scalable system 
possible. As there's no live connection to the database whilst the user is 
editing records you should be able to accomodate a lot of simultaneous 
users without a performance hit.

One last suggestion about the code below. You should be able to generalise 
the code so that you can use the same function to return recordsets for 
all your forms. All the Stored Procedures that I use for forms have a 
parameter named @intUID, which uniquely identifies the record I want. I 
then pass the Stored Procedure name and the UID to my general purpose 
function, which then returns the recordset I'm looking for.

Hope some of this helps!

Brian

> Thanks for your reply David.
T> hat sounds like an intersesting idea, I may give it a shot.
B> efore that though - my method 3 I can't test for performance as I can't 
f> igure out the code.
I>  want the afterupdate of the combo box to pass the recordID to the 
stored 
p> rocedure, and then change the recordsource of the form to the result of 
t> he stored procedure.

> what I have:

> after update of combobox:

> Private Sub LotNoFind_AfterUpdate()
'> Detail.Visible = True
'> Dim rs As Object
'>     Set rs = Me.Recordset.Clone
'>     rs.Find "[CATSGoodsInid] = " & Str(Me![LotNoFind])
'>     Me.Bookmark = rs.Bookmark
'>     rs.Close
'>     Set rs = Nothing

> Dim cmd1 As ADODB.Command
D> im prm1 As ADODB.Parameter

> Set cmd1 = New ADODB.Command

> With cmd1
 >    .ActiveConnection = CurrentProject.Connection
 >    .CommandText = "CATSspgGoodsInLookupLot"
 >    .CommandType = adCmdStoredProc
 >    Set prm1 = .CreateParameter("@GoodsInid", adInteger, adParamInput, 4)
 >    .Parameters.Append prm1
 >    prm1.Value = LotNoFind
E> nd With

> Dim rstTest As ADODB.Recordset
S> et rstTest = New ADODB.Recordset
 >    rstTest.Open cmd1
 >    Me.RecordSource = rstTest     ****returns error "Type Mismatch"

> End Sub

> 
t> he stored procedure:

> CREATE PROCEDURE CATSspgGoodsInLookupLot
	> (
	> 	@CATSGoodsInid  integer
	> )

>   AS

> SELECT * FROM CATSGoodsIn WHERE CATSGoodsInid = @CATSGoodsInid
G> O

> 
T> he first few lines of the afterupdate combobox are my method 1, ignore 
t> hem time being. I can't figure out why I get a Type Mismatch when 
running 
t> he after update on the combobox. Can you see what I'm doing wrong here ?
Message #4 by "Roddy Campbell" <scotiwis@b...> on Wed, 27 Mar 2002 01:20:47
wow Brian thanks for that. I'll come back to you on some of what you said 
above, meantime have amended code as per your suggestion, code is now:

Dim cmd1 As ADODB.Command
Dim prm1 As ADODB.Parameter
Set cmd1 = New ADODB.Command
With cmd1
    .ActiveConnection = CurrentProject.Connection
    .CommandText = "CATSspgGoodsInLookupLot"
    .CommandType = adCmdStoredProc
    Set prm1 = .CreateParameter("@GoodsInid", adInteger, adParamInput, 4)
    .Parameters.Append prm1
    prm1.Value = LotNoFind
End With
Dim rstTest As ADODB.Recordset
Set rstTest = New ADODB.Recordset
    rstTest.CursorLocation = adUseClient
    rstTest.Open cmd1
    Set Me.RecordSource = rstTest


when run the after update combo am now getting following compile error 
message:
invalid use of property - and it highlights ".Recordsource =" in the debug 
window.
Any ideas again ? Determined to get this to work.
Message #5 by brian.skelton@b... on Wed, 27 Mar 2002 10:20:30
Apologies Roddy. 

I was mistakenly looking through the Access XP help files last night - 
allowing you to run the code below is obviously one of the improvements 
they've made. In Access 2000, as far as I can figure out, you cannot 
assign the results of a stored procedure call to be the 
recordsource\rowsource of any access object.

What you have to do instead is to set the recordsource to a string that 
will call the relevant stored procedure. So your after_update code comes 
down to a single line:

Private Sub cmbFindRecord_AfterUpdate()

    Me.RecordSource = "EXEC CATSspgGoodsInLookupLot @GoodsInid=" & Me!
[cmbFindRecord]

End Sub


Message #6 by "Roddy Campbell" <scotiwis@b...> on Wed, 27 Mar 2002 11:01:52
Thanks Brian, I'll try this when I get home later on today.
What I was wondering meantime is if this replaces all of the ADO code, 
does this mean this way of doing it doesn't use ADO at all? I was told 
that must always use ADO connection for fastest retrieval of data on 
Access Project.
Thinking of upgrading to XP as seems it has more data handling 
cababilities in general.
Message #7 by "Roddy Campbell" <scotiwis@b...> on Wed, 27 Mar 2002 13:24:09
Brian tested code above and get "there was a problem accessing a property 
or method of the OLE object" runtime error. Tried it with:
Me.RecordSource = "exec CATSspgGoodsInLookupLot @GoodsInid=5" to see if 
that would work, get same error. Only works with:
Me.RecordSource = "CATSspgGoodsInLookupLot" but then prompts for parameter.
Any ideas? And where do I find help on this - is it msdn library on line, 
if so what do I search for or do you have other resources.
thanks
Message #8 by "Leo Scott" <leoscott@c...> on Wed, 27 Mar 2002 08:21:08 -0800
The recordsource property is expecting a string value like the SQL statement
that returned the recordset.

You could set it to

"SELECT * FROM TableName WHERE Criteria = " & cboBoxName.value

if the combobox has a string value in the first, probably hidden column,
then you must surround the cboBoxName.value with single quotes in the
returned string.  This might yeild good performance on the database if the
ID field is indexed and would not need a stored procedure to run.

|-----Original Message-----
|From: Roddy Campbell [mailto:scotiwis@b...]
|Sent: Wednesday, March 27, 2002 1:21 AM
|To: Access
|Subject: [access] Re: best way of using forms on Access Project - please
|advise
|
|
|wow Brian thanks for that. I'll come back to you on some of what you said
|above, meantime have amended code as per your suggestion, code is now:
|
|Dim cmd1 As ADODB.Command
|Dim prm1 As ADODB.Parameter
|Set cmd1 = New ADODB.Command
|With cmd1
|    .ActiveConnection = CurrentProject.Connection
|    .CommandText = "CATSspgGoodsInLookupLot"
|    .CommandType = adCmdStoredProc
|    Set prm1 = .CreateParameter("@GoodsInid", adInteger, adParamInput, 4)
|    .Parameters.Append prm1
|    prm1.Value = LotNoFind
|End With
|Dim rstTest As ADODB.Recordset
|Set rstTest = New ADODB.Recordset
|    rstTest.CursorLocation = adUseClient
|    rstTest.Open cmd1
|    Set Me.RecordSource = rstTest
|
|
|when run the after update combo am now getting following compile error
|message:
|invalid use of property - and it highlights ".Recordsource =" in the debug
|window.
|Any ideas again ? Determined to get this to work.
|

Message #9 by brian.skelton@b... on Thu, 28 Mar 2002 10:06:14
Well,I'm a bit puzzeled!

I copied this code straight from my database, where it worked perfectly.

Is your database small enough to email? I think I would be able to find 
the problem with a bit of 'hands on' work.

Help on Access Projects is extremly difficult to find. The Access help 
files are a joke. MSDN is slightly better, but you have to extrapolate 
from the VB articles.

I found Wrox's SQL Server with Access 2000 a good starting point. By no 
means perfect, but a good starting point. The Access Developers Handbook 
is said to have some excellent chapters on this, but I haven't updated my 
copy yet!

Brian

> Brian tested code above and get "there was a problem accessing a 
property 
o> r method of the OLE object" runtime error. Tried it with:
M> e.RecordSource = "exec CATSspgGoodsInLookupLot @GoodsInid=5" to see if 
t> hat would work, get same error. Only works with:
M> e.RecordSource = "CATSspgGoodsInLookupLot" but then prompts for 
parameter.
A> ny ideas? And where do I find help on this - is it msdn library on 
line, 
i> f so what do I search for or do you have other resources.
t> hanks
Message #10 by brian.skelton@b... on Thu, 28 Mar 2002 10:12:25
It's the equivalent of putting a query name in the recordsource.

The form must use it's own internal code to create a connection to the 
dataprovider, and presumably this is an ADO connection.

Brian

> Thanks Brian, I'll try this when I get home later on today.
W> hat I was wondering meantime is if this replaces all of the ADO code, 
d> oes this mean this way of doing it doesn't use ADO at all? I was told 
t> hat must always use ADO connection for fastest retrieval of data on 
A> ccess Project.
T> hinking of upgrading to XP as seems it has more data handling 
c> ababilities in general.
Message #11 by "Roddy Campbell" <scotiwis@b...> on Thu, 28 Mar 2002 14:45:01
Well thanks again Brian, after much tooing and froing I've decided on 
method 5(!)
I've got recordsource as stored proc which returns all records where 
LocationID = Location combo on my form. I have 24000 records in total, and 
these are split into various locations, eg Goods into USA, Goods into 
Scotland etc. So when I update location combo it fires stored proc 
returning all records where Location=combo location, the input parameter 
of form set to the combobox id. That way I'm getting a recordset of about 
4-5000 at a time, which access then works on in its cache. This seemed in 
practice faster than calling stored proc for every record, even on unbound 
form.

Only another prob has cropped up! I need the form to initially load with 
main location data showing as most people will use this. The OnOpen 
property of form sets Location combobox to 1 (main location) but only 1 
record comes up, the stored proc works fine once location combo is 
updated, but its as if when the form opens the stored proc fires before 
the combo is set to 1. Any ideas here ? (again!)
Message #12 by braxis@b... on Thu, 28 Mar 2002 17:40:10
The form loads its underlying data before any events can run - which 
explains why it's not working.

I can think of a couple of things to try:

1) Leave the recordsource of the saved form blank. Then set it in the Open 
event, after you've set the combobox value.

2) In your stored procedure, set a default on the comco cox parameter. 
Presumably the combobox is NULL when your form requests data from the 
stored procdeure. If you set a default, the stored procedure will use this 
value if passed a null and should return the recordset you want.

Brian

> Well thanks again Brian, after much tooing and froing I've decided on 
m> ethod 5(!)
I> 've got recordsource as stored proc which returns all records where 
L> ocationID = Location combo on my form. I have 24000 records in total, 
and 
t> hese are split into various locations, eg Goods into USA, Goods into 
S> cotland etc. So when I update location combo it fires stored proc 
r> eturning all records where Location=combo location, the input parameter 
o> f form set to the combobox id. That way I'm getting a recordset of 
about 
4> -5000 at a time, which access then works on in its cache. This seemed 
in 
p> ractice faster than calling stored proc for every record, even on 
unbound 
f> orm.

> Only another prob has cropped up! I need the form to initially load with 
m> ain location data showing as most people will use this. The OnOpen 
p> roperty of form sets Location combobox to 1 (main location) but only 1 
r> ecord comes up, the stored proc works fine once location combo is 
u> pdated, but its as if when the form opens the stored proc fires before 
t> he combo is set to 1. Any ideas here ? (again!)
Message #13 by "Roddy Campbell" <scotiwis@b...> on Thu, 28 Mar 2002 18:38:41
thanks, got that to work and tested thoroughly.
made no difference to speed, so think I'm going to stick with on form open:
recordsource = select * from GoodsIn where Location = 1
after update of location, recordsource becomes select * from GoodsIn where 
Location = combobox location id.
Tested this is the fastest and least complicated - unless anybody knows of 
a faster alternative ?

my next query:
I hear from many sources that stored procedures are the fastest possible 
way of retreiving data from a table. Should I use stored procedures 
instead of views? My view for the combo box for selecting individual 
records within the location is based on several tables. Would it be faster 
to take the SQL from this view and enter it as the code for a stored 
procedure and make the combo box based on this stored procedure (no 
parameters involved). Or do views exceed stored procedures when its just 
combining tables and selecting records?

And Brian, seeing as how you're coming to the end of a fairly large access 
project do you have any other tips for someone that is just starting out 
on one? Basically we've been running on Access2000 with linked tables to 
SQL2000 for few years - have a different mdb for each location we have and 
every time we took on a new location I had to duplicate the mdb and 
rewrite the code. Now combined all into one and started using Access 
project. Have about 20-30 tables, hundreds (help!) of queries which I'll 
have to re-write into SQL, and about 200 reports. We have such a 
complicated business the whole mdb's codes are written with a million 
different "after update on such and such a field do this", "if value on 
this form equals value on another form" etc etc, I reckon its going to 
take me best part of 6 or 7 months to re-write from scratch (problem being 
it was never designed in the first place - it just "evolved"). Anyway have 
reviewed the entire structure of the system and setup tables accordingly, 
its just the absolute mass of transferring all the 
queries/forms/reports/modules/code etc into access project that's the 
nightmare.
If you have any suggestions/tips would be most appreciated - I want this 
to be the be all and end all of systems that takes care of itself and 
might actually allow me a holiday for the first time in 3 years!
Priority from users is SPEED - instant retrieval of any data.

  Return to Index