I want the following query to work where [Tryme]
is a written rule that would be true or false so that I can run a table of QC things against it and get a table of all the, in this case, Employee
and check pairs that break my rules.
SELECT
Temp.*, FunctionIWant([Temp.TryMe]) AS Checked
FROM
(SELECT
Employee.ID, Employee.[First Name], Employee.[Last Name],
Employee.Wage, Employee.Tenure,
TheseRules.ID, TheseRules.Check AS Tryme
FROM
Employee, TheRules AS TheseRules) AS Temp;
Below is a statement that return with [Checked]
returning a boolean the way I want. The text written for the Checked
column is the exact text that is in Temp.Tryme
(to be more clear, "1.05*[Tenure]+37>[Wage]"
is the string)
SELECT
Temp.*, **1.05*[Tenure]+37>[Wage]** AS Checked
FROM
(SELECT
Employee.ID, Employee.[First Name], Employee.[Last Name], Employee.Wage,
Employee.Tenure, TheseRules.ID, TheseRules.Check AS Tryme
FROM
Employee, TheRules AS TheseRules) AS Temp;
Because it's just another level of evaluation than normal, I'm hoping this is possible.
I have tried Eval()
which either returns the string itself or #Error
.
I'm currently trying to create a function that would do it but I can't find out how to just give all the fields to the function for them to be evaluated there
For Eval() to work, would have to replace the string [Tenure] with value of field Tenure (likewise for Wage). Could possibly build a function that would receive field values (including expression string stored in Check field) and accomplish appropriate replace operations to produce an expression string that Eval() can process. I expect this will get rather complicated depending on the variety of "rules" to be evaluated.
Function could receive as arguments: data table name, record ID, calculation name, expression string. Open a recordset of given table filtered to ID. A SELECT CASE block would locate calculation name and perform replace operations on expression string pulling data from recordset fields.
Or abandon Rules table and have function hard code expressions. Pass to function data table name and record ID and calculation name. Still use a SELECT CASE but instead of Replace operations on a string, expressions just directly reference recordset fields. No Eval() function needed.
In either of those approaches, as "rules" are added, procedure will have to be expanded to accommodate. Avoiding this and streamlining procedure could use a "mapping" table that specifies field names and associated strings in expression they replace. Instead of SELECT CASE, open a recordset of the "mapping" table and loop its records to perform appropriate replace operations on string expression then Eval() can process the string.
Example of mapping table:
FldNme | FldMask | TblNme |
---|---|---|
Tenure | Tenure | Employees |
Wage | Wage | Employees |
Function:
Function CheckCalc(intI As Integer, strT As String, strE As String) As Boolean
Dim rsData As DAO.Recordset, rsMap As DAO.Recordset
Set rsData = CurrentDb.OpenRecordset("SELECT * FROM [" & strT & "] WHERE ID=" & intI)
Set rsMap = CurrentDb.OpenRecordset("SELECT * FROM ExpMap WHERE TblNme ='" & strT & "'")
Do While Not rsMap.EOF
strE = Replace(strE, rsMap!FldMask, rsData(rsMap!FldNme))
rsMap.MoveNext
Loop
CheckCalc = Eval(strE)
End Function
This assumes every table has key field named ID. If that is not the case, function will have to be modified to pass this field name as another argument and construct SQL statement with that variable. The mask in expression can be whatever you want, just make sure whatever is in the expression is in mapping table, such as [ ] characters, which I removed from expression in my testing and therefore is not seen in Mapping table.
If exact field name is used in expression as mask, could eliminate mapping table and its recordset. Procedure would instead loop through rsData fields and test with InStr() for its presence in expression string and if there, perform Replace operation.
Function CheckCalc(intI As Integer, strT As String, strE As String) As Boolean
Dim rsData As DAO.Recordset, fld As DAO.Field
Set rsData = CurrentDb.OpenRecordset("SELECT * FROM [" & strT & "] WHERE ID=" & intI)
For Each fld In rsData.Fields
If InStr(strE, fld.Name) Then
strE = Replace(strE, fld.Name, fld)
End If
Next
CheckCalc = Eval(strE)
End Function