对数据应用规则

本文关键字:规则 应用 数据 | 更新日期: 2023-09-27 18:04:45

在我的(C# + SQL Server)应用程序中,用户将能够在数据上定义规则,如:

ITEM_ID = 1 
OR (ITEM_NAME LIKE 'something' AND ITEM_PRICE > 123 
AND (ITEM_WEIGHT = 456 OR ITEM_HEIGHT < 789))

要验证的项集总是不同的,但它们的数量并不大。然而,规则的数量很高(假设是100000)。

如何检查哪些规则验证了给定的一组数字(同时考虑到性能)?

对数据应用规则

看起来你的"规则"或条件应该在c#中执行。

如果你真的要在SQL语句的WHERE子句中输入100,000个or和and,那么你将很难扩展你的应用程序。我只能想象索引的混乱,你必须有任意一组100,000个条件应用到数据集,并且每个排列都表现良好。

相反,我会运行一个基本的选择查询,读取每一行并在c#中过滤它。然后,您可以通过单独应用每个规则并跟踪通过/失败来跟踪每行通过和不通过的条件/规则。

当然,如果您正在查询一个非常大的表,那么性能可能会成为一个问题,但是您声明"要验证的项集…"不是一个巨大的数字,所以我认为这将是相对较快的把所有的数据表和执行你的规则代码,或应用一些基本的过滤在前面,然后在代码中更具体的过滤。


出于好奇,用户是如何输入这些"规则"的,比如:

ITEM_ID = 1
OR (ITEM_NAME LIKE 'something' AND ITEM_PRICE > 123
AND (ITEM_WEIGHT = 456 OR ITEM_HEIGHT < 789))

请告诉我他们没有输入实际的SQL查询(以文本形式),你只是将它们附加在一起,如:

var sql = "select * from myTable where ";
foreach(var rule in rules)
    sql += rule;

可能是某种规则构建器UI,构建这些sql语句?

你可以使用一些微软自己的T-SQL解析引擎。

可以在Microsoft.Data.Schema.ScriptDom.dllMicrosoft.Data.Schema.ScriptDom.Sql.dll中找到它们。

TSql100Parser parser = new TSql100Parser(false);
IList<ParseError> errors;
Expression expr = parser.ParseBooleanExpression(
        new StringReader(condition),
        out errors
    );
if (errors != null && errors.Count > 0)
{
    // Error handling
    return;
}

如果没有得到任何错误,则表示该字符串是一个有效的过滤器表达式。虽然可能会有一些有害的表达。

如果愿意,可以通过自己的访问者运行表达式来检测任何不需要的结构(如子查询)。但是要注意,对于Visit(...)ExplicitVisit(...),您必须重写几乎所有的650个重载。局部类在这里会很好。

当您满意时,可以构建一个完整的SELECT语句,包含所有表达式:

var schemaObject = new SchemaObjectName();
schemaObject.Identifiers.Add(new Identifier {Value = "MyTable"});
var queryExpression = new QuerySpecification();
queryExpression.FromClauses.Add(
    new SchemaObjectTableSource {SchemaObject = schemaObject});
// Add the expression from before (repeat as necessary) 
Literal zeroLiteral = new Literal
{
    LiteralType = LiteralType.Integer,
    Value = "0",
};
Literal oneLiteral = new Literal
{
    LiteralType = LiteralType.Integer,
    Value = "1",
};
WhenClause whenClause = new WhenClause
{
    WhenExpression = expr, // <-- here
    ThenExpression = oneLiteral,
};
CaseExpression caseExpression = new CaseExpression
{
    ElseExpression = zeroLiteral,
};
caseExpression.WhenClauses.Add(whenClause);
queryExpression.SelectElements.Add(caseExpression);
var selectStatement = new SelectStatement {QueryExpression = queryExpression};

…并将其全部转换成字符串:

var generator = new Sql100ScriptGenerator();
string query;
generator.GenerateScript(selectStatement, out query);
Console.WriteLine(query);
输出:

SELECT CASE WHEN ITEM_ID = 1
                 OR (ITEM_NAME LIKE 'something'
                     AND ITEM_PRICE > 123
                     AND (ITEM_WEIGHT = 456
                          OR ITEM_HEIGHT < 789)) THEN 1 ELSE 0 END
FROM   MyTable

如果这个表达式太大而无法处理,您可以将规则分割成块,每次只运行几个。


但是,要允许重新分发Microsoft.Data.Schema.ScriptDom.*.dll文件,您必须拥有Visual Studio Team System的许可证(至少包含在VS Pro/Ultimate中吗?)

链接:http://blogs.msdn.com/b/gertd/archive/2008/08/22/redist.aspx