Hi Ken,
Pyke supports user-defined knowledge bases. You can subclass knowledge_base and knowledge_entity_list (both defined in knowledge_base.py) to create your own types of knowledge bases. Pyke provides 4 sets of subclasses for fact bases (fact_base.py), question bases (question_base.py), rule bases (rule_base.py) and the "special" knowledge base (special.py). You can look at these 4 examples to see how to do the subclassing. These are each only a few hundred lines of code.
The knowledge_base subclass represents one knowledge base. This is the first name of the name1.name2(...) premises in your rules. For example, you could have just one knowledge base object for all of the facts in the database, or one per database table.
The knowledge_entity_list subclass represents all of the facts with the same name. These names are the name2 of name1.name2(...) in your rules. Again, you could make these correspond to table names, or column values, or whatever makes sense for you.
The lookup method returns a context manager wrapping a generator. You can use the closing context manager in the standard python contextlib library for the context manager. The generator yields (nothing) for each set of pattern variable bindings that match the goal presented to the lookup method. It binds the pattern variables, does the yield back to the caller, then unbinds the pattern variables for each matching fact.
You could create your own kind of knowledge base that does SQL queries for its fact lookups. If you only want facts in your database, look at fact_base.py as your main example. Facts are added in the fact_base class (add_universal_fact, add_case_specific_fact, assert_), and the lookup is done in the fact_list class (lookup).
To create the SELECT query, use the is_data method on each pattern passed to lookup to see if it is a data value or a pattern variable. Collect the data values (converting the pattern to the data value with the as_data method) to build your WHERE clause. Then collect the columns related to the pattern variables (is_data is False) in the SELECT clause. Loop on the returned rows binding the data returned in each row to the pattern variables using the match_data method. Be sure to mark the bindings and call undo_to_mark within a finally clause (so that it is done on exceptions, this is the reason for the context managers).
The pattern objects are defined in pattern.py, and the binding objects in contexts.py if you want to take a look. Basically, the patterns are static objects (immutable) that store all of the pattern variable bindings in a context (binding) object.
Hope this helps!
-Bruce