Gustav Brock
Gustav at cactus.dk
Thu Feb 19 09:41:41 CST 2009
Hi Rocky When you open a recordset it is read once into memory and Access doesn't reread the table if not needed. Seek is so fast that you can use it for recursive calls at amazing speed. Here's my old posting from 2002-02-06 on this. Note the use of a static recordset to keep it : <archive> Hi Bruce You have several options. One, however, won't do - as noted by Arthur - and that is a recursive query using SQL only; Access can't be fooled and will claim about a circular reference. Your only chance is to create a query resolving a limited number of levels only, say, 8 or 10. But you can cover the recursive call in a domain aggregate function like DLookup(). This is, however, very slow as DLookup() calling the query will run for each and every record. For more than some dozens of records this will most likely be unacceptable. The fastest way, for an unlimited number of levels, I've found is to create a lookup function which walks the tree for each record. This can output either the level of the record or a compound key build by the key of the record and all keys above. As the lookup function will use the same recordset for every call, you can make it static, and (for Jet) you can improve further by using Seek to locate the records. Here's an example which will give you an idea: <code> Function RecursiveLookup(ByVal lngID As Long) As String Static dbs As Database Static tbl As TableDef Static rst As Recordset Dim lngLevel As Long Dim strAccount As String If dbs Is Nothing Then ' For testing only. ' Replace with OpenDatabase of backend database file. Set dbs = CurrentDb() Set tbl = dbs.TableDefs("tblAccount") Set rst = dbs.OpenRecordset(tbl.Name, dbOpenTable) End If With rst .Index = "PrimaryKey" While lngID > 0 .Seek "=", lngID If Not .NoMatch Then lngLevel = lngLevel + 1 lngID = !MasterAccountFK.Value If lngID > 0 Then strAccount = str(!AccountID) & strAccount End If Else lngID = 0 End If Wend ' Leave recordset open. ' .Close End With ' Don't terminate static objects. ' Set rst = Nothing ' Set tbl = Nothing ' Set dbs = Nothing ' Alternative expression for returning the level. ' (Adjust vartype of return value of function.) ' RecursiveLookup = lngLevel ' As Long RecursiveLookup = strAccount End Function </code> This assumes a table with a primary key ID and a foreign (master) key pointing to the parent record - and a top level record (not used) with a visible key (AccountID) of 0. Now your tree will be nicely shown almost instantaneously using a query like this where Account will be the visible compound key: SELECT *, RecursiveLookup([ID]) AS Account FROM tblAccount WHERE (AccountID > 0) ORDER BY RecursiveLookup([ID]); /gustav > I am completely stymied on this one. Can any help, offer any code samples, > comments, etc, please? > > I have an n-level tree data structure implemented as a single table with a > set of recursive foreign keys, i.e. the table is related to itself in > several ways each way producing a different tree structure. Lets call these > "views". Any branch can be any depth. The order of the branches is, > relatively, unimportant as it is based purely on an alphabetic sort of the > branch title. > > I have a great form for maintaining the tree, using the treeview control. > This provides the desired navigation, display, edit etc. > > BUT, now I need to print each tree view as a report. I have tried creating > cascading queries as the recordsource - no dice, I don't know how many > levels a particular view will have. I have tried to create a report with a > recordset returning function as a recordsource, and cannot get this to work. </archive> /gustav >>> rockysmolin at bchacc.com 19-02-2009 16:23 >>> Fortunately this is a front end table so no going over the network. And I'm going to try Shamil's Seek approach - be a simple change. But you're right about it being faster in memory anyway. What I'm trying to do is stop the flashing and repainting. What I did yesterday is change the calls in the _Open event to: Echo False Scale the Form Translate the form Maximize the Form Echo On This seem to have had a real good effect on the forms. Also noticed that the first time I open a form I get one quick repaint (I'm using Chinese to test this because it using Unicode and seems to have a little more complexity) - the second time I open the form it's faster - almost like it was already translated even though I close the form on exit. Rocky Smolin Beach Access Software 858-259-4334 www.e-z-mrp.com www.bchacc.com -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of jwcolby Sent: Thursday, February 19, 2009 4:49 AM To: Access Developers discussion and problem solving Subject: Re: [AccessD] Find First in an Array? Rocky, A table may or may not be "noticeably slower" however you have already said that you had issues. Once you cache the data, getting data out of a cache structure will be 100 to 1000 times faster. Remember that a table is NOT cached (though a disconnected ADO recordset is I guess). DAO requires a trip to the disk OVER THE NETWORK (if any). As for going back to the beginning, please do but do not let it stop you from implementing what I will build for you. Just remember that a class object is just like any other object in Access (cbo, recordset, query) it is just a tool that anyone can use once built. I will do the building for this instance. John W. Colby www.ColbyConsulting.com Rocky Smolin at Beach Access Software wrote: > I'm wondering if an array or collection will be noticeably faster than > a recordset since there are about 2500 records in the controls table > and so it's probably all in memory already. The fields are not > indexed - so I'll bet I could get a little boost in performance by > indexing the fields I search on. > > OTOH, it's a good opportunity to learn something about classes. I'll > post the table layout tomorrow. But I think to be fair to John and > anyone else who wants to help, I should go back to all those saved > emails on the classes class and start from the beginning.