A SQL-based Rule Engine allows you to define validation logic as data instead of hard-coded procedures. This is extremely useful in ERP, CRM, WMS, finance, banking, healthcare, and dynamic form engines where business rules change frequently but deployments are slow or expensive.
This article explains how to design a dynamic rule engine stored entirely in SQL with:
Rule definition tables
Condition groups
Dynamic SQL evaluation
Parameter injection
Runtime orchestration
Exception logging
Flowcharts + architecture diagrams
1. Core Problem
Business logic changes often:
“If Quantity > Stock → throw error”
“If Customer.CreditLimit < Order.Total → fail”
“If Item.Category = ‘Hazardous’ → require special approval”
“If Vendor is blocked → stop PO creation”
Traditionally:
Developers change code → deploy → test → release.
Better approach:
Store rules in tables → interpret them dynamically → no deployments needed.
2. High-Level Architecture
┌────────────────────────┐
│ Application Layer │
│ (API, UI, Microservices)│
└─────────────┬───────────┘
│
┌───────────┴────────────┐
│ Rule Engine Layer │
│ (SQL Stored Procedure) │
└───────┬─────────────────┘
│
┌────────────────┴────────────────────┐
│ Rule Definition Tables │
│ - Rules │
│ - RuleConditions │
│ - RuleConditionGroups │
│ - RuleSeverity │
│ - EntityFieldCatalog │
└─────────────────────────────────────┘
3. Rule Engine Table Design
Below is a battle-tested schema used in real enterprise systems.
3.1 Rule Table (Rule Master)
Stores the rule metadata.
CREATE TABLE RuleMaster (
RuleId INT IDENTITY PRIMARY KEY,
RuleName VARCHAR(200),
EntityName VARCHAR(200), -- “SalesOrder”, “Stockline”, etc.
IsActive BIT DEFAULT 1,
Severity VARCHAR(30), -- "Error", "Warning", "Info"
ErrorMessage VARCHAR(500),
CreatedDate DATETIME2 DEFAULT SYSDATETIME()
);
Examples:
“SO_Total_Validation”
“Stock_Availability_Check”
“PO_Block_Vendor_Validation”
3.2 Rule Condition Groups
Groups allow AND/OR nesting.
CREATE TABLE RuleConditionGroup (
GroupId INT IDENTITY PRIMARY KEY,
RuleId INT FOREIGN KEY REFERENCES RuleMaster(RuleId),
GroupOperator VARCHAR(5) CHECK (GroupOperator IN ('AND','OR'))
);
Example:
Group 1: Quantity > 0 AND Price > 0
Group 2: Customer.CreditLimit < Order.Total
3.3 Rule Conditions
Each group contains conditions stored as rows, not code.
CREATE TABLE RuleCondition (
ConditionId INT IDENTITY PRIMARY KEY,
GroupId INT FOREIGN KEY REFERENCES RuleConditionGroup(GroupId),
LeftOperand VARCHAR(200), -- Field name, JSON path, SQL expression
Operator VARCHAR(10), -- =, <>, >, <, >=, LIKE, IN, BETWEEN, etc.
RightOperand VARCHAR(200), -- Literal value or field-to-field
DataType VARCHAR(20), -- Int, Decimal, Date, NVarchar
);
Example rows:
| LeftOperand | Operator | RightOperand | DataType |
|---|---|---|---|
| OrderTotal | > | CreditLimit | Decimal |
| Status | <> | 'Closed' | NVARCHAR |
| Quantity | <= | StockQty | Int |
4. Rule Orchestration Table (Optional but Recommended)
Allows mapping rules to events:
CREATE TABLE RuleEventMapping (
Id INT IDENTITY PRIMARY KEY,
RuleId INT FOREIGN KEY REFERENCES RuleMaster(RuleId),
EventName VARCHAR(200) -- "OnCreate", "OnUpdate", "OnSubmit"
);

Join the conversation! Your thoughts help the community grow.