Solved

MSAccess 2010 global variables in user defined aggregate VBA functions

Posted on 2014-01-07
7
1,025 Views
Last Modified: 2014-01-30
Okay so I have an issue with Access.  Which is not uncommon but this one is bugging me a bit.  So here is a simplified version of the problem.  The real data is too messy for short stories.  I think this problem requires some background to understand so I'm describing it as best I can.  

I have a database loaded with objects that have identifying fields and a single string field, call it a description of the object.  See the CSV table below.

category, type, color,desc
1,a,b,new
1,a,b,old
1,a,b,new
1,a,b,new
2,a,r,new
3,b,g,old

The data needs to be grouped by the first 3 fields (category, type, color).  So I run a SQL query that groups the data, as seen below.  Then use a custom VBA aggregate function to concatenate the string values of each item together.

SELECT
 FIRST(category),
 FIRST(type),
 FIRST(color),
 LAST(fconcat(desc,(category&type&color)))
FROM table1
GROUP BY category, type, color;

LAST(fconcat(desc,(category&type&color))) is where the fun comes in...  

So the first time I built this solution I simply used a global variable in fconcat to determine if the ids were the same as the last iteration.  

If so the data from the last iteration is pulled from another global variable, the new string from the current iteration is concatenated with the old, stored in the same global variables and fconcat returns the latest complete string.  

If ids differ from the last iteration the global variables are overwritten with the new and the new string is returned unaltered.  

Because fconcat is wrapped by LAST the data from the most recent iteration for each grouping are used in the results.  So I ended up with the complete strings.  

That was fine for the first table.  But a different table caused some fun results.  For some reason on this table the iterations occur in a different order than the grouping.  So all the strings from one set of items come at different times mixed in with the other groups.  This means the previous iteration has no logical (at least on the layer I'm working at) connection to the current iteration.  Global variables become practically useless.  Well if VB had better arrays it wouldn't be a big deal.

So my solution was to use a table to temporarily store the data as the iterations come in and always return the latest concatenation of the groups on every iteration.  It worked fine.  

But I wasn't out of the woods yet.  What happens when data in the temp table isn't cleaned up and the scope of the code isn't enough to tell the difference between new and old data?  All kinds of fun things of course.  

So I used a global variable (uhg...) to determine if this is the first iteration and if so clear out the table before continuing.  

Well that worked with mixed results.  The problem is the global variables are cleared in a way I don't understand.  

If the query runs to completion then is closed and reopened.  The global variables are preserved and the function fails to recognize it is a new run.  

If the query breaks during execution the variables are cleared.  So reopening the query means the flag in the global variable doesn't exist and it knows to clear the temp data table.  

Well I want it to recognize when it is on the first iteration of an execution so it can clear the temp data table and run clean.  And that is the problem this whole thing was about.  

How do I identify the first iteration inside a custom VBA aggregate function?  Or maybe clean up after myself instead, how do I identify the last?  OR is there a better method of achieving my result all together.  All I want to do is concatenate those silly strings.  Something like GROUP_CONCAT() from MySQL would be nice...  

My current solution is to prefix some characters, in the case below 'store1', to the fconcat call so it doesn't step on the toes of other instances within the overall query execution.  

LAST(fconcat(desc,('store1'&category&type&color)))

The data does not change between running instances of Access so overlapping new and old data in this context is not a big issue.  The function also contains logic to discard repetitive entries so running the query twice without cleaning up in between yields the correct results but I don't like it.  

I'm open to cleaner solutions.
0
Comment
Question by:RTM_TSI
7 Comments
 
LVL 30

Expert Comment

by:hnasr
ID: 39764093
Upload a sample database and explain what do you expect using this sample database.
0
 
LVL 84
ID: 39764806
Like hnasr, I'm a bit confused.

But to your issue of global variables, instead of using them you can use the hidden form trick.

Create a form that opens when your database opens. In that form, add a Textbox named something like "txQueryIteration". Instead of writing to your global variable, write to that textbox:

Forms("MyHiddenForm").txQueryIteration = 1

This value won't be reset when errors occur, so you always have it available.
0
 
LVL 47

Accepted Solution

by:
Dale Fye (Access MVP) earned 500 total points
ID: 39764887
Personally, I would try the following first.

SELECT category, type, color, fconcat(desc,(category&type&color)))
FROM (
SELECT category, type, color
FROM table1
GROUP BY category, type, color
) as DistGroup

This assume that your fconcat() function already knows what table to find these fields in.

Most concat functions like this create a query that limits the recordset to those records which match the passed criteria ([Category]&[type]&[Color]) and then loop through the recordset, concatenating the values in some other field (or combination of fields), in your case [Desc]

Give it a try.
0
Backup Your Microsoft Windows Server®

Backup all your Microsoft Windows Server – on-premises, in remote locations, in private and hybrid clouds. Your entire Windows Server will be backed up in one easy step with patented, block-level disk imaging. We achieve RTOs (recovery time objectives) as low as 15 seconds.

 

Author Comment

by:RTM_TSI
ID: 39765066
Fyed, I like it.  Makes perfect sense.  I could actually pass fconcat the target field, table name, and WHERE clause to make it work for most situations.  I will give it a shot tonight and post my results.
0
 
LVL 46

Expert Comment

by:Martin Liss
ID: 39821545
I've requested that this question be closed as follows:

Accepted answer: 500 points for fyed's comment #a39764887

for the following reason:

This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0
 

Author Closing Comment

by:RTM_TSI
ID: 39821546
Great outside of the box approach.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
In Microsoft Access, learn how to “cascade” or have the displayed data of one combo control depend upon what’s entered in another. Base the dependent combo on a query for its row source: Add a reference to the first combo on the form as criteria i…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

919 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now