将规则应用于数据

时间:2011-08-08 17:15:09

标签: c# sql

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

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

要验证的项目集总是不同,但它们不是很大的数字。但是,规则的数量很高(比方说,100000)。

如何查看一组给定数字验证的规则(也考虑到考虑到性能)?

2 个答案:

答案 0 :(得分:2)

这看起来像你的“规则”或条件应该用C#来执行。

如果您真的要将100,000个OR和AND提供给SQL语句的WHERE子句,那么扩展应用程序将非常困难。我只能想象你必须要将任意一组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的语句?

答案 1 :(得分:1)

您可以将一些Microsoft自己的解析引擎用于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