We had a similar need for a RULES engine in our database.
The RULES engine allowed us to place data in various tables, and then, compile the rule from the data in the tables to generate and store a SQL text statement that when executed generates results.
I think you could use the same approach.
For this we had the following tables:
1. RULE - PK is a RULE_ID. Gave a name for the rule and a long varchar string for the Compiled Rule text.
2. MATCHING_EXPRESSION - This table lists all the matching expression that are part of the rule. It has a FK into RULE and has an int ORDINAL column so one knows the "order" of the matching expressions within the rule. Each matching expression has: MATCHABLE_FIELD_ID fk (see next table def), OPERATOR_ID FK (see table def), MATCHING_CRITERIA varchar and optional (nullable) NEXT_OPERATOR_ID (for stringing togheter expressions), oh and ORDINAL (int). The MATCHING_EXPRESSIONs get strung together to generate the syntax of a compiled rule.
3. MATCHATABLE_FIELD table describes the datatype of a matchable field, the name of the field (usually the column name from a table) and a Table name. You want your rules to work against real tables and real column values from your db and it is the MATCHABLE_FIELD table that gives the list of tables and columns that can be used when constructing rules. This table typically holds static list you set up once and extend only when you change your DB model.
4. OPERATOR table provides the list of operators. All you need here is a NAME and a SYMBOL. (And AND, Or OR, Like LIKE, Equal =, Not Equal !=) are all tupples for this table. These are typically a static list you set up once. The name is used for display purposes and the SYMBOL for construction of the SQL text.
5. MATCHABLE_FILED_TO_OPERATOR is an associative table that has FKs into MATCHABLE_FILE and OPERATOR. It defines for each field the list of "allowable" operators. For example, integer columns can have =, !=, <, >, >=, <=, but LIKE wouldn't make sense. This table typically holds static list you set up once and extend only when you change your DB model.
Now, all you need is a SP (stored proc) that given a RULE_ID "generates and stores" the SQL text which is the rule. That is a little complex to write, but it is doable (I have done it).
This approach works quite well. And you can easily envision a UI that allows for the generation of rules, what with the name of a rule entered, and a series of dropdowns for selecting the matchable field, then for selecting the appropriate operator and a textbox for matching criteria...followed by an operator of AND, OR before adding in the next matching expression, etc.
This worked quite well for us and provided sophisticated rules to be generated. However, we DID NOT support parenthesis, but that would have been a relatively easy thing to add. I think one way to support that would be to add a precendence "tree". In this approach instead of MATCHING_EXPRESSION having a LIST of tupples for a rule and an ordinal, remove ORDINAL and make it a tree...RULE would have a ROOT_MATCHING_EXPRESSION_ID FK, and then each MATCHING_EXPRESSION record would have nullable LEFT and RIGHT children FKs back to itself.
Good luck.
TR