1

My Problem is this:

I would like to use a custom ribbon Command button or even a simple command button inside the spreadsheet to initialize an OLEDB database connection and update/recalculate all the assoicated user defined functions that require such a connection, or those specified by me. I do not want any of these functions to recalculate except for when the specific button is clicked. I am having difficulty figuring out how to do this. Kindly offer your assistance or suggestions.

See below for Details on what I have done:

I currently store data within an access database from which I use vba in excel to make specific queries. I have embedded each datarequest routine within a group of functions under a module by the name [fnc]. I then access them as user-defined functions from within the excel spreadsheet. An example is given here:

 Function ValueV(mm As String, yy As String, qtable As String, qcode As String, compare_period As Integer, average_period As Integer, weight As Boolean) As Variant
 'Month Value Formula for Horizontal Data
 'mm - month value 2-digit
 'yy - year value 4-digit
 'qtable - query table name eg. "cpia"
 'qcode - query code for variable eg. "all0100"
 'avgperiod - lag periods to average in calculation eg. 3-avgperiods for quarterly measure, 1-avgperiod for point measure.
 'weight - boolean (true or false) value for weighting values given reference weight. Currently unsupported. Code should be extended to include this feature. (space holder for now)
  Dim lag_value As Variant
  Dim cur_value As Variant
  lag_value = 0
  cur_value = 0


     'STEP-A: Gets the initial Value average or not.
     '===============================================================
     If compare_period > 0 Then
     'Use this step to pickup initial value when compare_period <> 0 which requires a % change as opposed to a point value.
     'Average_period must be greater than or equal to one (1). One (1) represents the current month which is the same as a point value.
         lmm = fnc.lagdate(mm, yy, compare_period, "mm")                          'lag month (a single month for mValueH)
         lyy = fnc.lagdate(mm, yy, compare_period, "yy")                          'lag year (a single month for mValueH)
         smm = fnc.lagdate(mm, yy, compare_period + average_period - 1, "mm")     'dating backwards to account for average period
         syy = fnc.lagdate(mm, yy, compare_period + average_period - 1, "yy")     'dating backwards to account for average period
         'note, for smm & syy, the average period includes the lmm so we add back one (1)
         'eg. 3-mth average is not 3-lags but current and 2-lags.
         sdate1 = syy & fnc.numtext(smm)
         'start date for query (begining of lag value including average period)

         Set MyRecordset = New ADODB.Recordset
         MySql = sql.sqlVSers(lmm, lyy, qtable, qcode, sdate1)
         'MsgBox (MySql)
         MyRecordset.Open MySql, MyConnect, adOpenStatic, adLockReadOnly

         Do Until MyRecordset.EOF     'Loop to end and enter required values
         lag_value = lag_value + MyRecordset(qcode)
         MyRecordset.MoveNext
         Loop
         'Stop
         lag_value = lag_value / average_period
         MyRecordset.Close
     End If


     'STEP-B: Gets the current Value average or not.
     '===============================================================
         smm = fnc.lagdate(mm, yy, average_period - 1, "mm")           'dating backwards to account for average period
         syy = fnc.lagdate(mm, yy, average_period - 1, "yy")           'dating backwards to account for average period
         sdate1 = syy & fnc.numtext(smm)
         'start date for query (begining of lag value including average period)

         Set MyRecordset = New ADODB.Recordset
         MySql = sql.sqlVSers(mm, yy, qtable, qcode, sdate1)
         MyRecordset.Open MySql, MyConnect, adOpenStatic, adLockReadOnly

         Do Until MyRecordset.EOF     'Loop to end and enter required values
         cur_value = cur_value + MyRecordset(qcode)
         MyRecordset.MoveNext
         Loop

         cur_value = cur_value / average_period
         MyRecordset.Close


     'STEP-C: Calculates the Requested % Change or Point Value.
     '===============================================================
     If compare_period = 0 Then
         ValueV = cur_value
     Else
         ValueV = cur_value / lag_value * 100 - 100
     End If

 End Function

Since I totally bypass the use of a subroutine, the connection to the database is currently done as a workbook helper routine as shown below.

Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim filePath
filePath = ThisWorkbook.Path
If Right$(filePath, 1) <> "\" Then filePath = filePath & "\"
MyConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & filePath & "rsdata.accdb;"
End Sub

Problem is, this updating process is less than desirable. Idealy, I would like to position a custom button inside the menu bar that (upon clicking it) will connect to the database and recalculate all the userdefined functions that are used in a given worksheet or workbook.

Please offer your suggestions or point to where something like this may have been done before.

Thanks in advance. JR.

  • One way to "control" this is by defining a global variable (e.g. Recalc = True/False) or named cell. Set the variable through a user interaction. It is difficult to control when to set the variable back to False though (can't be part of the UDF, unless you count that every cell with a UDF has been recalculated) – Robert Ilbrink Mar 25 '13 at 06:03

1 Answers1

1

You are trying to use UDF's for something they are not designed to do. What they are designed to do is behave just like other cell formula, and be calcutaed when Excel decides they need to be.

You have two options

  • redesign your application to not use UDF's (IMO the best way)
  • modify your UDFs to only respond to a trigger specified by you, eg a button click (IMO a cludge and generally bad idea)

How to redesign to avoid UDF's depend on factors not disclosed in your OP

chris neilsen
  • 52,446
  • 10
  • 84
  • 123